How to implement Asp.net IdentityUser with breezejs NHibernate - fluent-nhibernate

I am working with a project that leverage Breezejs and NHibernate. I implemented Asp.Net IdentityUser in my entity model.
Anytime i tried to generate metedata, insert or update my model, using breeze NHContext. a foreign key not match exception is always thrown. Please, how do i use Fluent mapping in my code in order get over this NorthBreeze limitation

When using NHibernate with Breeze, the foreign keys must be mapped to properties of your entity class. That is so the foreign keys can will be available on the client. For the IdentityUserClaim entity, you would need something like this:
public class IdentityUserClaim : EntityWithTypedId<int>
{
public virtual string ClaimType { get; set; }
public virtual string ClaimValue { get; set; }
public virtual IdentityUser User { get; set; }
// foreign key property
public virtual int UserId { get; set; }
}
public class IdentityUserClaimMap : ClassMapping<IdentityUserClaim>
{
public IdentityUserClaimMap()
{
Table("AspNetUserClaims");
Id(x => x.Id, m => m.Generator(Generators.Identity));
Property(x => x.ClaimType);
Property(x => x.ClaimValue);
ManyToOne(x => x.User, m => m.Column("User_Id"));
// foreign key mapping
Property(x = x.UserId).Column("User_Id").Not.Insert().Not.Update();
}
}
Note the foreign key is mapped with insert=false and update=false. Updates to the User_Id column go through the normal NHiberate flow (i.e. they are controlled by the related User entity). The UserId property is used only to expose the foreign key value to Breeze.

Related

Entity Framework 6 says two entries have the same primary key, while they are in completely different tables

Edit 1: So I wasn't getting anywhere and tried something different. I renamed my FriendRequest class to FriendRequestBase and made it abstract and then I made a FriendRequest class that inherits from FriendRequestBase without any extra fields, so now the inheritance looks like this:
FriendRequest : FriendRequestBase
GroupModRequest : FriendRequestBase
That should work, right? Well now, I added a migration to see if it will add any changes and yes, for some reason it now starts dropping foreign keys.
DropForeignKey("dbo.GroupModRequests", "SenderID", "dbo.AspNetUsers");
DropForeignKey("dbo.GroupModRequests", "ReceiverID", "dbo.AspNetUsers");
What could be the problem there? I've correctly set up the foreign keys with the Fluent API:
modelBuilder.Entity<GroupModRequest>()
.HasRequired(r => r.Receiver)
.WithMany()
.HasForeignKey(k => k.ReceiverID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<GroupModRequest>()
.HasRequired(r => r.Sender)
.WithMany()
.HasForeignKey(k => k.SenderID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<GroupModRequest>()
.HasRequired(r => r.Group)
.WithMany(g => g.GroupModRequests)
.HasForeignKey(k => k.GroupID)
.WillCascadeOnDelete(true);
I'm trying to seed my database after running 'update-database' and this is what I'm getting:
All objects in the EntitySet 'ApplicationDbContext.FriendRequests'
must have unique primary keys. However, an instance of type
'AW.Models.GroupModRequest' and an instance of type
'AW.Models.FriendRequest' both have the same primary key value,
'EntitySet=FriendRequests;SenderID=a9540bd6-8532-4c7a-9f68-19d2aeecffcb;ReceiverID=8f50eccf-8ccf-432e-a033-82d933b5e3f5'.
As I mentioned previously, FriendRequests are in one table and GroupModRequests are in a different table so this error doesn't make sense. I can kind of guess why this happens, though.
GroupModRequests inherits from FriendRequests and I'm using the Table-Per-Conrete-Class approach, meaning that FriendRequests has a table and GroupModRequests has a table and it has all of the properties FriendRequests have plus some more. Note, that FriendRequests isn't an abstract class.
FriendRequests has a composite primary key consisting of: SenderID, ReceiverID.
GroupModRequests has a composite primary key consisting of: SenderID, ReceiverID and GroupID.
And so I bet that for some reason it is ignoring the 'GroupID' part of the key and ignoring the fact that they are in different tables and throws this error when a FriendRequest has the same Sender/Receiver ID as a GroupModRequest.
So how can I fix this in EF6? I already set this with fluent, but apparently that isn't enough:
modelBuilder.Entity<GroupModRequest>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("GroupModRequests");
});
The composite keys look like this:
public class FriendRequest
{
[Key, Column(Order = 1)]
public string SenderID { get; set; }
[ForeignKey("SenderID")]
public virtual ApplicationUser Sender { get; set; }
[Key, Column(Order = 2)]
public string ReceiverID { get; set; }
[ForeignKey("ReceiverID")]
public virtual ApplicationUser Receiver { get; set; }
}
public class GroupModRequest : FriendRequest
{
[Key, Column(Order = 3)]
public Guid GroupID { get; set; }
public virtual Group Group { get; set; }
}
Note: I also have 'LocationModRequests' which inherits from FriendRequests as well and is almost the same as GroupModRequests, if it matters.

Fluent NHibernate mapping foreign key

I have a db that I'm trying to model using Fluent NHibernate.
the tables in questions are:
User:
PK Id, Name, FK accessType, FK authorization
AccessType:
PK Id, Name
Authorization:
PK Id, Name
Permission:
PK Id, FK menuId, FK accessId, FK authId
User Entity:
public Users()
{
Permissions = new List<Permissions>();
}
public virtual AccessTypes AccessType { get; set; }
public virtual Authorization Authorization { get; set; }
public virtual string Name { get; set; }
public virtual IList<Permissions> Permissions { get; set; }
Permission Entity:
public class Permissions : EntityWithTypedId<long>
{
public virtual Menus Menu { get; set; }
public virtual AccessTypes AccessType { get; set; }
public virtual Authorization Authorization { get; set; }
}
User Map:
public UsersMap()
{
Table("USERS");
Map(x => x.Name, "NAME");
References<AccessTypes>(x => x.AccessType, "ACCESS_TYPE_ID");
References<Authorization>(x => x.Authorization, "AUTHORIZATION_ID");
Id(x => x.Id, "ID")
.Column("ID")
.GeneratedBy.Assigned();
HasMany<Permissions>(x => x.Permissions)
.KeyColumns.Add("ACCESS_TYPE_ID", "AUTHORIZATION_ID")
.Inverse()
.Cascade.None();
}
Permission Map:
public PermissionsMap()
{
ReadOnly();
Table("PERMISSIONS");
References<Menus>(x => x.Menu, "MENU_ID");
References<AccessTypes>(x => x.AccessType, "ACCESS_TYPE_ID");
References<Authorization>(x => x.Authorization, "AUTHORIZATION_ID");
Id(x => x.Id, "ID")
.Column("ID")
.GeneratedBy.Assigned();
}
I got this error: Foreign key (FK79B2A3E83BA4D9E3:PERMISSIONS [ACCESS_TYPE_ID, AUTHORIZATION_ID])) must have same number of columns as the referenced primary key (USERS [ID])
I need to get a list of permission by checking the user accessType and user authorization.
My question is: How can I map the Permission list in User mapping? Should I Use the ternary association?
Does anyone have any insight on how to do this?
This scenario is not supported. NHibernate has a feature called property-ref which can be used (but should be avoided) on old databases that were designed poorly. However, property-ref only supports referencing one non-primary-key column. Since you are trying to reference two such columns, this will not work.
However, since the permissions are obviously not tied to the user per se, you should not even map them.
You could still have the property for the list in the Users class and fill that with an extra method that simply reads the Permissions using a Where-condition on both columns. Still, I would advise against this. I would write a method like this (code not tested):
public IList<Permissions> GetPermissionsForUser(Users user)
{
return session.QueryOver<Permissions>()
.Where(p => p.Authorization.Equals(user.Authorization))
.And(p => p.AccessType.Equals(user.AccessType)).List();
}

Fluent NHibernate Mapping - Composite Key

I'm trying to map the following tables/entities in FNH and seem to be getting nowhere fast!
**Tables**
Contacts
ID (PK - int - generated)
...
PhoneTypes
ID (PK - varchar - assigned) (e.g. MOBILE, FAX)
ContactPhones
ContactRefId (PK - FK to Contacts)
PhoneTypeRefId (PK - FK to PhoneTypes)
...
(I should note that I am also using the S#arp Architecture framework)
**Entities**
public class Contact : Entity
{
(The ID property is defined in the Entity base class and is type int)
public virtual ICollection<ContactPhone> PhoneNumbers { get; set; }
}
public class PhoneType : EntityWithTypedId<string>, IHasAssignedId<string>
{
(The ID property is defined in the base class and is type string)
....
}
public class ContactPhone : EntityWithTypedId<ContactPhoneId>, IHasAssignedId<ContactPhoneId>
{
public virtual Contact Contact { get; set; }
public virtual PhoneType PhoneType { get; set; }
....
}
I read that it is advisable when working with composite ids, to separate the composite id into a different class.
hibernate composite key
public class ContactPhoneId : EntityWithTypedId<ContactPhoneId>, IHasAssignedId<ContactPhoneId>
{
public virtual Contact Contact { get; set; }
public virtual PhoneType PhoneType { get; set; }
}
...I could just make this class serializable and override
Equals and GetHashCode myself instead of using the S#arp Arch base class.
I've tried so many combinations of mappings that I'm now completely confused.
This is my latest shot:
public class ContactMap : IAutoMappingOverride<Contact>
{
public void Override(AutoMapping<Contact> mapping)
{
mapping.HasMany<ContactPhone>(x => x.PhoneNumbers)
.KeyColumns.Add("ContactRefId")
.KeyColumns.Add("PhoneTypeRefId")
.AsSet()
.Inverse()
.Cascade.All();
}
}
public class PhoneTypeMap : IAutoMappingOverride<PhoneType>
{
public void Override(AutoMapping<PhoneType> mapping)
{
mapping.Id(x => x.Id).Column("Id").GeneratedBy.Assigned();
}
}
public class ContactPhoneMap : IAutoMappingOverride<ContactPhone>
{
public void Override(AutoMapping<ContactPhone> mapping)
{
mapping.Table("ContactPhones");
mapping.CompositeId<ContactPhoneId>(x => x.Id)
.KeyReference(y => y.Contact, "ContactRefId")
.KeyReference(y => y.PhoneType, "PhoneTypeRefId");
}
}
I've had many exceptions thrown when trying to generate the mappings, the latest of which is:
Foreign key (FK672D91AE7F050F12:ContactPhones [ContactRefId, PhoneTypeRefId]))
must have same number of columns as the referenced primary key (Contacts [Id])
Does anyone see anything obvious that I'm doing wrong? I'm new to NH and FNH, which may be obvious from this post. :-) Also, has anyone used Composite Ids like this while using S#arp Architecture? What are the best practices (other than to use surrogate keys :-) ) ?
Many thanks...and sorry about the long post.
I have a many to many relationship too. I've got mine setup like this:
mapping.HasManyToMany(x => x.Artists).Cascade.All().Inverse().Table("ArtistImages");
The ArtistImages table has primary keys for tables Artists and Images.

Add multi-column unique constraint on foreign Key using fluent-nhibernate automapping

I'm an NHibernate and fluent-nhibernate newbie. And I've got some problem with unique constraint and nhibernate mapping.
I've got the following part of domain model.
public class Batch
{
public virtual int Id {get; set;}
public virtual string Name {get; set;}
public virtual IList<BatchParameter> BatchParameters {get; set;}
}
public class BatchParameter
{
public virtual int Id {get; set;}
public virtual string Name {get; set;}
public virtual Batch Batch {get; set;}
}
I'm trying to use fluent-nhibernate to map it on the db (SQLServer) using automapping.
I want to be set up my db in order to have :
Primary Keys on the "Id"s properties
a Foreign Key on the BatchParamets table
a Unique Constraint on the Batch table on column Name
a Unique Constraint on the BatchParameters table on columns Name and Batch_Id
So I've written down this code:
public class BatchMapping : IAutoMappingOverride<Batch>
{
public void Override(FluentNHibernate.Automapping.AutoMapping<Batch> mapping)
{
mapping.Id( b => b.Id);
mapping.HasMany<BatchParameter>(p => p.BatchParameters).Cascade.All().Inverse();
}
}
public class BatchParameterMapping : IAutoMappingOverride<BatchParameter>
{
public void Override(FluentNHibernate.Automapping.AutoMapping<BatchParameter> mapping)
{
mapping.Id( b => b.Id);
mapping.Map(b => b.Name).Unique();
//mapping.Map(p => p.Name).UniqueKey("Batch_Parameter");
//mapping.Map(p => p.Batch.Id).UniqueKey("Batch_Parameter");
}
}
No problems for the primary keys, the foreign key and the first Unique Constraint. A little bit of headache for the Unique Constraint.
Can someone show me the straight way???
Thanks!
First, it looks like you have a copy-and-paste error: ...Map(b => b.Name)... should go in BatchMapping, not BatchParameterMapping.
public class BatchMapping : IAutoMappingOverride<Batch>
{
public void Override(AutoMapping<Batch> mapping)
{
mapping.Map(b => b.Name).Unique();
}
}
Next, BatchParameter.Batch is a many-to-one relationship from BatchParameter to Batch, so it should be mapped with References(...) instead of Map(...). You use References for foreign keys to another entity and use Map for simple properties.
public class BatchParameterMapping : IAutoMappingOverride<BatchParameter>
{
public void Override(AutoMapping<BatchParameter> mapping)
{
mapping.Map(p => p.Name).UniqueKey("Batch_Parameter");
mapping.References(p => p.Batch).UniqueKey("Batch_Parameter");
}
}
Finally, you should remove the unnecessary mappings for the Id properties and Batch.BatchParameters. Fluent NHibernate's auto-mapping will map them as desired by default. In your Override methods you only need to specify the properties where you want to do something differently than the auto-mapping default, such as specifying unique keys.
If Id and Name are primary keys in your BatchParameter table you would need a composite id. Also if you want to have a reference back to Batch from your BatchParameter class you will need to use Reference. The following should be close to what you need:
public class BatchParameterMapping : IAutoMappingOverride<BatchParameter>
{
public void Override(FluentNHibernate.Automapping.AutoMapping<BatchParameter> mapping)
{
mapping.CompositeId()
.KeyProperty(x => x.Id)
.KeyProperty(x => x.Name);
mapping.References(x => x.Batch);
}
}

Fluent NHibernate: How to create one-to-many bidirectional mapping?

Basic question: How to I create a bidirectional one-to-many map in Fluent NHibernate?
Details:
I have a parent object with many children. In my case, it is meaningless for the child to not have a parent, so in the database, I would like the foreign key to the parent to have NOT NULL constraint. I am auto-generating my database from the Fluent NHibernate mapping.
I have a parent with many child objects like so:
public class Summary
{
public int id {get; protected set;}
public IList<Detail> Details {get; protected set;}
}
public class Detail
{
public int id {get; protected set;}
public string ItemName {get; set;}
/* public Summary Owner {get; protected set;} */ //I think this might be needed for bidirectional mapping?
}
Here is the mapping I started with:
public class SummaryMap : ClassMap<Summary>
{
public SummaryMap()
{
Id(x => x.ID);
HasMany<Detail>(x => x.Details);
}
}
public class DetailMap : ClassMap<Detail>
{
public DetailMap()
{
Id(x => x.ID);
Map(x => x.ItemName).CanNotBeNull();
}
}
In the Detail table, the Summary_id should be Not Null, because in my
case it is meaningless to have a Detail object not attached to the
summary object. However, just using the HasMany() map leaves the Summary_id foreign key nullable.
I found in the NHibernate docs (http://www.hibernate.org/hib_docs/nhibernate/html/collections.html) that "If the parent is required, use a bidirectional one-to-many association".
So how do I create the bidirectional one-to-many map in Fluent NHibernate?
To get a bidirectional association with a not-null foreign key column in the Details table you can add the suggested Owner property, a References(...).CanNotBeNull() mapping in the DetailsMap class, and make the Summary end inverse.
To avoid having two different foreign key columns for the two association directions, you can either specify the column names manually or name the properties in a way that gives the same column name for both directions. In this case you I suggest renaming the Details.Owner property to Details.Summary.
I made the Summary id generated by increment to avoid problems when inserting into the table since Summary currenty has no columns besides id.
Domain:
public class Detail
{
public int id { get; protected set; }
public string ItemName { get; set; }
// Renamed to use same column name as specified in the mapping of Summary.Details
public Summary Summary {get; set;}
}
public class Summary
{
public Summary()
{
Details = new List<Detail>();
}
public int id { get; protected set; }
public IList<Detail> Details { get; protected set; }
}
Mapping:
public class DetailMap : ClassMap<Detail>
{
public DetailMap()
{
Id(x => x.id)
.GeneratedBy.Native();
Map(x => x.ItemName)
.CanNotBeNull();
References<Summary>(x => x.Summary)
// If you don't want to rename the property in Summary,
// you can do this instead:
// .TheColumnNameIs("Summary_id")
.CanNotBeNull();
}
}
public class SummaryMap : ClassMap<Summary>
{
public SummaryMap()
{
Id(x => x.id)
.GeneratedBy.Increment();
HasMany<Detail>(x => x.Details)
.IsInverse()
.AsBag(); // Use bag instead of list to avoid index updating issues
}
}