If you haven't setup a Fluent NHibernate project before, you should checkout the GettingStarted: Introduction guide.
As mentioned in ClassMap, all mappings are done from inside the constructor of a ClassMap<T>
derived class; so baring that in mind, all examples are going to exclude the surrounding class.
There are three relationships you can use to map between your entities, reference (many-to-one), has many (one-to-many), and has many to many (many-to-many); I'll start by discussing the exclusive features for each, then show the features that are common to both.
The References
method is used to create a many-to-one
relationship between two entities; that's where the current entity has a single property that is an instance of the other entity.
Here's a typical example of a References
usage.
// schema table Account ( // our entity CustomerId int foreign key (Customer) references (Id) ) table Customer ( Id int identity(1,1) primary key ) // model public class Account { public Customer Customer { get; set; } } // mapping public AccountMap() { References(x => x.Customer); }
This creates a relationship between the two tables. In NHibernate hbm mapping, it's equivalent to <many-to-one name="Customer" />
.
If you're generating your schema from your mappings (see Schema Generation), you may want to name your foreign key, you can do that using the WithForeginKey
method.
References(x => x.Customer) .WithForeignKey();
This creates a foreign key based on the naming of your entities; if this example were an Account
that has a Customer
, the foreign key would be called FK_Account_Customer
. If you would prefer to specify your own key, you can use the WithForeignKey(string)
overload.
If your foreign key Id has a different column name than what you're using for a property, then you can use the ColumnName
method.
// schema table Account ( // our entity Customer_RefId int foregin key (Customer) references (Id) ) table Customer ( Id int identity(1,1) primary key ) // model public Customer Customer { get; set; } // mapping References(x => x.Customer) .ColumnName("Customer_RefId");
If you need to specify multiple columns to use as a key, useful if the entity you're referencing has a composite-id, then you can use the WithColumns
method.
References(x => x.Customer) .WithColumns("CustomerName", "CustomerReference");
If you need to link to the entity you're referencing by something other than it's primary key, then you can use the PropertyRef
method.
References(x => x.Customer) .PropertyRef(x => x.CustomerReference);
If it's allowed in your domain for a foreign key to be null, you may want to stipulate what behavior NHibernate should use on encountering a null; you can do this with theNotFound
property.
References(x => x.Customer) .NotFound.Ignore();
The default behavior is Exception
.
The HasMany
method is used to create a one-to-many
relationship between two entities; that's where the current entity has a collection of instances of the other entity.
Here's a typical example of a HasMany
usage.
// schema table Account ( // our entity Id int identity(1, 1) primary key ) table Customer ( AccountId int foreign key (Account) references (Id) ) // model public class Account { public IList<Customer> Customers { get; private set; } public Account() { Customers = new List<Customer>(); } } // mapping public AccountMap() { HasMany(x => x.Customers); }
This creates a relationship between the two tables. In NHibernate hbm mapping, it's equivalent to:
<bag name="Customers"> <key column="AccountId" /> <one-to-many class="Account" /> </bag>
If you need to specify multiple columns to use as a key, useful if the entity you're referencing has a composite-id, then you can use the WithKeyColumns
method.
HasMany(x => x.Customers) . WithKeyColumns("CustomerName", "CustomerReference");
Similarly, if you just want to specify one column name you can use WithKeyColumn
.
The HasManyToMany
method is used to create a many-to-many
relationship between two entities; that's where there's a reference between two tables, with an intermediary table.
Here's a typical example of a HasManyToMany
usage.
// schema table Account ( // our entity Id int identity(1, 1) primary key ) table AccountToCustomer ( Account_id int foreign key (Account) references (Id) Customer_id int foreign key (Customer) references (Id) ) table Customer ( Id int identity(1, 1) primary key ) // model public class Account { public IList<Customer> Customers { get; private set; } public Account() { Customers = new List<Customer>(); } } // mapping public AccountMap() { HasManyToMany(x => x.Customers); }
This creates a relationship between the two tables. In NHibernate hbm mapping, it's equivalent to:
<bag name="Customers"> <key column="Customer_id" /> <many-to-many class="Account" column="Account_id" /> </bag>
If your design has a different intermediary table name, you can use the WithTableName
method to set it.
HasManyToMany(x => x.Customers) .WithTableName("CustomerAddresses");
If you need to override the foreign key names that are used in the intermediary table, you can use WithParentKeyColumn
and WithChildKeyColumn
.
table AccountToCustomer ( Account_RefId int foreign key (Account) references (Id) Customer_RefId int foreign key (Customer) references (Id) ) HasMany(x => x.Customers) .WithParentKeyColumn("Account_RefId") .WithChildKeyColumn("Customer_RefId");
You can use either of these methods, or both together.
These settings are common to either all the relationships, or just the HasMany
and HasManyToMany
; I'll specify which relationships they're for.
For all relationships
If your entity uses a backing field for a property, or some other non-standard design, then you can map it using the Access
property.
// model public class Account { private IList<Customer> customers = new List<Customer>(); public IList<Customer> Customers { get { return customers; } } } // mapping HasMany(x => x.Customers) .Access.AsCamelCaseField();
The Access
property can be used to set various combinations of Field
and Property
, with various casings and prefixes.
For example, for the same mapping but with the field called _customers
you could use the Prefix.Underscore
overload: Access.AsCamelCaseField(Prefix.Underscore)
.
For all relationships
If you need to specify how joined entities are fetched, then you can use the Fetch
property.
HasMany(x => x.Customers) .Fetch.Join();
The options are Join
and Select
.
For all relationships
HasMany(x => x.Customers) .Inverse();
This sets the inverse
attribute.
For all relationships
HasMany(x => x.Customers) .Cascade.All();
This sets the cascade
attribute; the options are All
, None
, SaveUpdate
, Delete
, and AllDeleteOrphan
(for HasMany
and HasManyToMany
only).
For HasMany
and HasManyToMany
only
You can override the type of collection that is used for relationships, you can read more about this in Standard Mapping Collection Types.
The default is to use bag
, but you can override it with the explicit methods.
HasMany(x => x.Customers) .AsSet();