We have a multi-tenant database - i.e. common database used by multiple clients, hence each table will have a "ClientID" column indicating the Tenant.
We are using Fluent NHibernate for ORM and looking for the best approach to tackle multi-tenancy: each Mapping class needs to map ClientID, however, the value would come from the User Account object - i.e. from User Session of some sort.
Is there a nice and easy way to achieve this using Fluent NHibernate? If so, could you provide an example?
I'm not entirely sure if this is what your asking but if you need each class to map to the ClientId, here's one example.
Basically, each class would have a UserAccount property or whatever class is going to store the user's account information that has the ClientId property on it. Then in your Fluent NHibernate mapping, you can map the classes together using the References() method. See example below:
public class UserAccount
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Bill> Bills { get; set; }
}
public class Bill
{
public virtual int BillId { get; set; }
public virtual UserAccount User { get; set; }
}
public class UserAccount : ClassMap<UserAccount>
{
public UserAccount()
{
Id( x => x.Id ).Column( "ClientId" );
Map( x => x.Name );
HasMany( x => x.Bills );
}
}
public class BillMap : ClassMap<Bill>
{
public BillMap()
{
Id( x => x.Id ).Column( "BillId" );
References( x => x.User ).Column( "ClientId" );
}
}
So in your Bill table, you would have a ClientId column which in database terms is really a foreign key referencing the UserAccount table's primary key column which would also be named ClientId.
If you are truly going to have a large amount of tables that are all going to have a ClientId column, you also have the option of abstracting that out to a base class that your entities inherit from that would already have the UserAccount property on it. You could do the same base class approach for your Fluent NHibernate mapping files as well.
Related
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.
I'm having issues with Nhibernate persisting a HasOne Relationship for one of my entities with Cascade.None() in effect. My domain model involves 4 classes listed below.
public class Project
{
public virtual int Id {get;set;}
public virtual IList<ProjectRole> Team { get; protected set; }
}
public class ProjectRole
{
public virtual int Id { get; set; }
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
public class Role
{
public virtual int Id { get; set; }
public virtual string Value { get; set; }
}
public class User
{
public virtual int Id { get; protected set; }
public virtual string LoginName { get; set; }
}
So basically we have projects, which have a list of ProjectRoles available from the Team property. Each ProjectRole links a User to the specific Role they play on that project.
I'm trying to setup the following cascade relationships for these entities.
project.HasMany<ProjectRoles>(p=> p.Team).Cascade.All()
projectRole.HasOne<Role>(r => r.Role).Cascade.None()
projectRole.HasOne<User>(r => r.User).Cascade.SaveUpdate()
I've used fluent nhibernate overrides to setup the cascades as above, but I'm finding that the line
projectRole.HasOne<Role>(r => r.Role).Cascade.None()
is resulting in the ProjectRole.Role property not being saved to the database. I've diagnosed this be looking at the SQL Generated by Nhibernate and I can see that the "Role_id" column in the ProjectRoles table is never set on update or insert.
I've also tried using
projectRole.HasOne<Role>(r => r.Role).Cascade.SaveUpdate()
but that fails as well. Unfortunately leaving it Cascade.All() is not an option as that results in the system deleting the Role objects when I try to delete a project role.
Any idea how to setup Cascade.None() for the ProjectRole-> Role relationship with out breaking persistence.
HasOne is for a one-to-one relationship which are rare. You want to use References to declare the one side of a one-to-many relationship. Making some assumptions about your domain model, the mapping should look like:
project.HasMany<ProjectRoles>(p=> p.Team).Inverse().Cascade.AllDeleteOrphan()
projectRole.References<Role>(r => r.Role);
projectRole.References<User>(r => r.User);
See also this question about the difference between HasOne and References.
I'm trying to figure out how to structure my entity mappings to achieve the following:
public class Document
{
public virtual string Name { get; set; }
// Other properties
public IList<Document> RelatedDocuments { get; set; }
}
I'd like to have a relationship table that has ID pairs of the related Documents.
Right now I'm addressing this problem with the solution described in this SO question: Fluent Nhibernate mapping related items (crazy coincidence that the OP's name is the same as mine).
I'd rather have a single list of related items and not have to have one for RelatedTo and one for RelatedFrom. Is that possible?
To clarify, the problem I'm looking to solve is that if I relate Document A to Document B, I need Document A's RelatedDocuments list to have Document B in it, and Document B's RelatedDocuments list to have Document A in it, without having to create two relationships.
Try something like this:
class Document
{
public int Id { get; set; }
public string Name { get; set; }
public IList<Document> Related { get; set; }
public void RelateTo(Document other)
{
this.Related.Add(other);
other.Related.Add(this);
}
}
class DocumentMap : FluentNHibernate.Mapping.ClassMap<Document>
{
public DocumentMap()
{
Table("Documents");
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Related)
.Table("DocumentRelations")
.ParentKeyColumn("DocumentId")
.ChildKeyColumn("RelatedDocumentId");
}
}
The DocumentRelations table is the association table which specifies that RelatedDocumentId is related to DocumentId. The tables would look like:
create table Documents
(
Id int identity primary key clustered,
Name varchar(100)
)
create table DocumentRelations
(
DocumentId int,
RelatedDocumentId int,
primary key clustered (DocumentId,RelatedDocumentId)
)
You should consider whether you need to have any data associated with the relationship itself. In that case, the related collection would be a collection of RelatedDocument instances which would have the related document as a property and the mapping would be HasMany.
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.
I'm trying to use the table-per-subclass (which fluent-nhibernate automaps by default) with a class structure like the following:
public class Product
{
public virtual int Id{ get; set; }
public virtual string Title{ get; set; }
}
public class ProductPackage : Product
{
public ProductPackage(){ Includes = new List<Product>(); }
public virtual IList<Prodcut> Includes{ get; private set; }
[EditorBrowsable( EditorBrowsableState.Never )]
public class ProductPackageAutoOverride : IAutoMappingOverride<ProductPackage>
{
public void Override( AutoMap<ProductPackage> mapping )
{
mapping.HasManyToMany( x => x.Includes )
.WithTableName( "IncludesXProduct" )
.WithParentKeyColumn( "ProductId" )
.WithChildKeyColumn( "IncludesProductId" )
.Cascade.SaveUpdate();
}
}
}
Instead of adding a new table "IncludesXProduct" to represent the many-to-many mapping, it adds a property "ProductPackageId" to the Product table. Of course persisting to this schema doesn't work.
Have I missed something simple or is this type of thing not really supported by NHibernate?
It is possible to do this with NHibernate. Unfortunately my fluent syntax isn't very good, but it looks like FNH is somehow regarding the relationship as a many-to-one rather than a many-to-many.
If you tag your question with "fluent-nhibernate" then you may get more knowledgeable people answering.