Fluent NHibernate Wiki
Im>JamesGregory
mNo edit summary
Tags: Visual edit apiedit
 
(23 intermediate revisions by 10 users not shown)
Line 1: Line 1:
 
__TOC__
 
__TOC__
   
Fluent mapping is the de-facto mapping style that Fluent NHibernate uses. It's a [http://martinfowler.com/bliki/FluentInterface.html fluent interface] that allows you to map your entities completely in code, with all the compile-time safety and refactorability that brings.
+
Fluent mapping is the namesake mapping style that Fluent NHibernate uses. It's a [http://martinfowler.com/bliki/FluentInterface.html fluent interface] that allows you to map your entities completely in code, with all the compile-time safety and refactorability that brings.
   
 
The [[getting started|getting started guide]] has a good introduction to mapping with the fluent interface. Once you've read that then you should be able to find a bit more detail here.
 
The [[getting started|getting started guide]] has a good introduction to mapping with the fluent interface. Once you've read that then you should be able to find a bit more detail here.
Line 19: Line 19:
   
 
Inside the constructor is where you map the various properties of your entity.
 
Inside the constructor is where you map the various properties of your entity.
 
== Mappings ==
 
   
 
<blockquote>Every mapping inside a <code>ClassMap<T></code> is built using lambda expressions, which allow us to reference the properties on your entities without sacrificing compile-time safety. The lambdas typically take the form of <code>x => x.Property</code>; the <code>x</code> on the left is the parameter declaration, which will be the entity you're mapping, while the <code>x.Property</code> is accessing a property on your entity (coincidently called Property in this case). You'll quickly get used to these lambdas, as they're used ''everywhere'' in Fluent NHibernate.</blockquote>
 
<blockquote>Every mapping inside a <code>ClassMap<T></code> is built using lambda expressions, which allow us to reference the properties on your entities without sacrificing compile-time safety. The lambdas typically take the form of <code>x => x.Property</code>; the <code>x</code> on the left is the parameter declaration, which will be the entity you're mapping, while the <code>x.Property</code> is accessing a property on your entity (coincidently called Property in this case). You'll quickly get used to these lambdas, as they're used ''everywhere'' in Fluent NHibernate.</blockquote>
   
Once you've declared your <code>ClassMap<T></code> you're going to need to map the properties on your entity. There are several methods available that map your properties in different ways, and each one of those is a [http://martinfowler.com/dslwip/MethodChaining.html method chain] that you can use to customise the individual mapping.
+
Once you have declared your <code>ClassMap<T></code> you're going to need to map the properties on your entity. There are several methods available that map your properties in different ways, and each one of those is a [http://martinfowler.com/dslwip/MethodChaining.html method chain] that you can use to customise the individual mapping.
   
=== Id ===
+
== Id ==
   
 
Every mapping requires an Id of some kind, these are mapped using the <code>Id</code> method; this method takes a lambda expression of the property you want to use as your Id. Depending on the return type of the property you supply, Fluent NHibernate will make some assumptions about the kind of identifier you're using. For example, if your Id property is an <code>int</code>, then we assume you're using an identity column; similarly, if you use a <code>Guid</code> then we assume it's a [http://nhforge.org/blogs/nhibernate/archive/2009/05/21/using-the-guid-comb-identifier-strategy.aspx Guid Comb].
 
Every mapping requires an Id of some kind, these are mapped using the <code>Id</code> method; this method takes a lambda expression of the property you want to use as your Id. Depending on the return type of the property you supply, Fluent NHibernate will make some assumptions about the kind of identifier you're using. For example, if your Id property is an <code>int</code>, then we assume you're using an identity column; similarly, if you use a <code>Guid</code> then we assume it's a [http://nhforge.org/blogs/nhibernate/archive/2009/05/21/using-the-guid-comb-identifier-strategy.aspx Guid Comb].
Line 46: Line 44:
 
<blockquote>Fluent NHibernate's interface is designed for discoverability. Everything you need should be easy to find "under" the declaring method using method chains.</blockquote>
 
<blockquote>Fluent NHibernate's interface is designed for discoverability. Everything you need should be easy to find "under" the declaring method using method chains.</blockquote>
   
 
== Properties ==
You can read more about mapping identities in the [[Fluent mapping identities|identities page]].
 
 
=== Properties ===
 
   
 
Property mappings make up a large amount of any mapped domain, so it's best that you know how to map them. They're just as simple as identities, except we use the <code>Map</code> method.
 
Property mappings make up a large amount of any mapped domain, so it's best that you know how to map them. They're just as simple as identities, except we use the <code>Map</code> method.
Line 55: Line 51:
 
Map(x => x.FirstName);
 
Map(x => x.FirstName);
 
</source>
 
</source>
  +
  +
That's all you need for most situations. Fluent NHibernate knows what the return type of your property is, and assumes that the column it's mapping against will have the same name as the property itself. There are numerous customisations available through methods chained from the <code>Map</code> call. For example, if you're generating your schema you may want to specify whether the column itself is nullable, you can do that by using the <code>Nullable</code> method and (optionally) the <code>Not</code> operator property.
  +
  +
<source lang="csharp">
  +
// nullable
  +
Map(x => x.FirstName)
  +
.Nullable();
  +
  +
// not nullable
  +
Map(x => x.FirstName)
  +
.Not.Nullable();
  +
</source>
  +
  +
If you need to map private properties, you can read about our situation [[fluent mapping private properties|here]].
  +
  +
== Relationships ==
  +
  +
Apart from the most basic of domains, nearly every situation will require mapping some form of relationship. The main ones you'll normally use are many-to-one's, one-to-many's, and many-to-many's. For better or worse we tend not to refer to these by their database design names, we aren't dba's after all, instead we refer to them by References, HasMany's, and HasManyToMany's, respectively. We'll go into each in more detail next.
  +
  +
=== References / many-to-one ===
  +
  +
References is for creating many-to-one relationships between two entities; you're ''referencing'' another entity, so you use the <code>References</code> method. A reference is to a single instance of an entity, if you're mapping a collection then you need either [[#HasMany / one-to-many|HasMany]] or an [[#HasManyToMany / many-to-many|HasManyToMany]] which can be viewed as the "other side" of the References relationship.
  +
  +
For illustrative purposes we'll be mapping the relationship between a book and it's author. In database terms that would be a book table with a foreign key column referencing the primary key of a author table.
  +
  +
<source lang="csharp">
  +
public class Book
  +
{
  +
public Author Author { get; set; }
  +
}
  +
</source>
  +
  +
The following is what you'd use inside the constructor of your Book [[#ClassMap|mapping]]:
  +
  +
<source lang="csharp">
  +
References(x => x.Author);
  +
</source>
  +
  +
That's it, you've now created a references relationship between book and author. The foreign-key is assumed to be named <code>Author_id</code> in your book table, if that isn't to your liking you can use the <code>Column</code> method.
  +
  +
As with all other fluent mappings, you can chain calls to customise the reference relationship. For example if you wanted to specify the cascade strategy you'd use the <code>Cascade</code> property.
  +
  +
<source lang="csharp">
  +
References(x => x.Author)
  +
.Column("AuthorId")
  +
.Cascade.All();
  +
</source>
  +
  +
=== HasMany / one-to-many ===
  +
  +
HasMany is probably the most common collection-based relationship you're going to use; a HasMany is the "other side" of a [[#References / many-to-one|References]] relationship. Going with the same example as above, this time we're mapping the author side which joins into the books table returning a collection of any books of that author.
  +
  +
<source lang="csharp">
  +
public class Author
  +
{
  +
public IList<Book> Books { get; set; }
  +
}
  +
</source>
  +
  +
To map this we use the <code>HasMany</code> method, as so:
  +
  +
<source lang="csharp">
  +
HasMany(x => x.Books);
  +
</source>
  +
  +
As with References, the foreign-key defaults to <code>Author_id</code>, and you can override it with the <code>KeyColumn</code> method.
  +
  +
There are a few different types of collections you can use, and they're all available under the HasMany call. You can read about them [[fluent mapping collection types|here]].
  +
  +
=== HasManyToMany / many-to-many ===
  +
  +
HasManyToMany works exactly the same as [[#HasMany / one-to-many]], except the underlying database structure it maps to is different.
  +
  +
<source lang="csharp">
  +
HasManyToMany(x => x.Books);
  +
</source>
  +
  +
There are a few different types of collections you can use, and they're all available under the HasManyToMany call. You can read about them [[fluent mapping collection types|here]].
  +
  +
=== HasOne / one-to-one ===
  +
  +
HasOne is usually reserved for a special case, generally you'd use a [[#References / many-to-one|References]] in most situations (see: [http://blog.jagregory.com/2009/01/27/i-think-you-mean-a-many-to-one-sir/ I think you mean a many-to-one]). If you really do want a one-to-one, then you can use the <code>HasOne</code> method.
  +
  +
<source lang="csharp">
  +
HasOne(x => x.Cover);
  +
</source>
  +
  +
=== Any ===
  +
  +
Any really only should be used if you know what you're doing. To quote the [http://www.nhforge.org/doc/nh/en/index.html#mapping-types-anymapping NHibernate documentation]:
  +
  +
<blockquote>The <code><any></code> mapping element defines a polymorphic association to classes from multiple tables. This type of mapping always requires more than one column. The first column holds the type of the associated entity. The remaining columns hold the identifier. It is impossible to specify a foreign key constraint for this kind of association, so this is most certainly not meant as the usual way of mapping (polymorphic) associations. You should use this only in very special cases (eg. audit logs, user session data, etc).</blockquote>
  +
  +
There are three things you need to provide to be able to map using an Any; a column that holds the type of the entitiy, at least one column holding the identifier value, and a type for the identifier itself. You can specify these using the <code>EntityTypeColumn</code>, <code>EntityIdentifierColumn</code>, and <code>IdentityType</code> methods respectively.
  +
  +
<source lang="csharp">
  +
ReferencesAny(x => x.Author)
  +
.EntityTypeColumn("Type")
  +
.EntityIdentifierColumn("Id")
  +
.IdentityType<int>();
  +
</source>
  +
  +
== Components ==
  +
  +
Components are a clever way of mapping a normalized data model into a more reasonable object model. You may have a customer table that has a series of address columns, ideally you'd want the address columns to be mapped into an Address object, rather than just being properties on a Customer; you can do that with components.
  +
  +
The <code>Component</code> method takes two parameters, rather than just one like the rest of the methods you've seen so far. The first parameter is a property accessor lambda, like all the other methods, and the second one is another lambda (quite often referred to as a nested-closure in these situations) that defines a new scope for defining the mappings of that particular sub-part (in this case the component).
  +
  +
<source lang="csharp">
  +
Component(x => x.Address, m =>
  +
{
  +
m.Map(x => x.Number);
  +
m.Map(x => x.Street);
  +
m.Map(x => x.PostCode);
  +
});
  +
</source>
  +
  +
As you can see, the first parameter references the <code>Address</code> property on our entity, which is the property that holds our component. The second property is where we define what makes up the component. The main difference in this lower scope is that you have to use the <code>m</code> instance to access the available methods; you don't have to call it <code>m</code>, but we are for brevity.
  +
  +
In this case we've mapped a component (stored in the Address property), that's made up of three properties (Number, Street, and PostCode); these properties are stored in the same table as the parent entity in a normalized fashion.
  +
  +
== Subclasses ==
  +
  +
Subclasses work in a very similar way to [[#ClassMap|ClassMap's]], in that you create a derived class which you put your mappings in; it's just you use <code>SubclassMap</code> instead of <code>ClassMap</code>.
  +
  +
There are two strategies for mapping inheritance hierarchies in Fluent NHibernate, table-per-class-hierarchy and table-per-subclass; the former being a subclass, and the latter a joined-subclass.
  +
  +
Table-per-subclass is the default mapping for subclasses, so unless you say otherwise you'll have a separate table per-subclass. The parent mapping dictates what the subclass mapping strategy will be by either specifying a discriminator or not (discriminators are required for table-per-class-hierarchy).
  +
  +
We'll use the following two classes for examples:
  +
  +
<source lang="csharp">
  +
public class Parent
  +
{
  +
public int Id { get; set; }
  +
public string Name { get; set; }
  +
}
  +
  +
public class Child : Parent
  +
{
  +
public string AnotherProperty { get; set; }
  +
}
  +
</source>
  +
  +
If you wanted to map this as a table-per-subclass, you'd do it like this:
  +
  +
<source lang="csharp">
  +
public class ParentMap : ClassMap<Parent>
  +
{
  +
public ParentMap()
  +
{
  +
Id(x => x.Id);
  +
Map(x => x.Name);
  +
}
  +
}
  +
  +
public class ChildMap : SubclassMap<Child>
  +
{
  +
public ChildMap()
  +
{
  +
Map(x => x.AnotherProperty);
  +
}
  +
}
  +
</source>
  +
  +
That's all there is to it, parent and child are now mapped as subclasses. When Fluent NHibernate finds ChildMap it knows that it's a subclass of Parent.
  +
  +
If you wanted to do a table-per-class-hierarchy strategy, then you just need to specify the discriminator column in your ClassMap.
  +
  +
<source lang="csharp">
  +
public class ParentMap : ClassMap<Parent>
  +
{
  +
public ParentMap()
  +
{
  +
Id(x => x.Id);
  +
Map(x => x.Name);
  +
  +
DiscriminateSubclassesOnColumn("type");
  +
}
  +
}
  +
  +
public class ChildMap : SubclassMap<Child>
  +
{
  +
public ChildMap()
  +
{
  +
Map(x => x.AnotherProperty);
  +
}
  +
}
  +
</source>
  +
  +
The only difference is in ParentMap we're now calling <code>DiscriminateSubclassesOnColumn</code> with a <code>"type"</code> parameter; this parameter is the column name in the table which dictates what class each row represents.

Latest revision as of 09:15, 11 August 2016

Fluent mapping is the namesake mapping style that Fluent NHibernate uses. It's a fluent interface that allows you to map your entities completely in code, with all the compile-time safety and refactorability that brings.

The getting started guide has a good introduction to mapping with the fluent interface. Once you've read that then you should be able to find a bit more detail here.

ClassMap[]

ClassMap<T> is the basis of all your mappings, you derive from this to map anything.

public class PersonMap : ClassMap<Person>
{
  public PersonMap()
  {
  }
}

Inside the constructor is where you map the various properties of your entity.

Every mapping inside a ClassMap<T> is built using lambda expressions, which allow us to reference the properties on your entities without sacrificing compile-time safety. The lambdas typically take the form of x => x.Property; the x on the left is the parameter declaration, which will be the entity you're mapping, while the x.Property is accessing a property on your entity (coincidently called Property in this case). You'll quickly get used to these lambdas, as they're used everywhere in Fluent NHibernate.

Once you have declared your ClassMap<T> you're going to need to map the properties on your entity. There are several methods available that map your properties in different ways, and each one of those is a method chain that you can use to customise the individual mapping.

Id[]

Every mapping requires an Id of some kind, these are mapped using the Id method; this method takes a lambda expression of the property you want to use as your Id. Depending on the return type of the property you supply, Fluent NHibernate will make some assumptions about the kind of identifier you're using. For example, if your Id property is an int, then we assume you're using an identity column; similarly, if you use a Guid then we assume it's a Guid Comb.

Id(x => x.Id);

That's the most common scenario for mapping your Id. Customisations can be done by chaining methods off the Id call. For example, if we were to need to change what column the property maps to we could use the Column method, or for explicitly specifying the identity generator you could use the GeneratedBy property.

Id(x => x.Id)
  .Column("PersonId")
  .GeneratedBy.Assigned();

In this example we're specifying that the Id property is mapped to a PersonId column in the database, and it's using an assigned generator.

Fluent NHibernate's interface is designed for discoverability. Everything you need should be easy to find "under" the declaring method using method chains.

Properties[]

Property mappings make up a large amount of any mapped domain, so it's best that you know how to map them. They're just as simple as identities, except we use the Map method.

Map(x => x.FirstName);

That's all you need for most situations. Fluent NHibernate knows what the return type of your property is, and assumes that the column it's mapping against will have the same name as the property itself. There are numerous customisations available through methods chained from the Map call. For example, if you're generating your schema you may want to specify whether the column itself is nullable, you can do that by using the Nullable method and (optionally) the Not operator property.

// nullable
Map(x => x.FirstName)
  .Nullable();

// not nullable
Map(x => x.FirstName)
  .Not.Nullable();

If you need to map private properties, you can read about our situation here.

Relationships[]

Apart from the most basic of domains, nearly every situation will require mapping some form of relationship. The main ones you'll normally use are many-to-one's, one-to-many's, and many-to-many's. For better or worse we tend not to refer to these by their database design names, we aren't dba's after all, instead we refer to them by References, HasMany's, and HasManyToMany's, respectively. We'll go into each in more detail next.

References / many-to-one[]

References is for creating many-to-one relationships between two entities; you're referencing another entity, so you use the References method. A reference is to a single instance of an entity, if you're mapping a collection then you need either HasMany or an HasManyToMany which can be viewed as the "other side" of the References relationship.

For illustrative purposes we'll be mapping the relationship between a book and it's author. In database terms that would be a book table with a foreign key column referencing the primary key of a author table.

public class Book
{
  public Author Author { get; set; }
}

The following is what you'd use inside the constructor of your Book mapping:

References(x => x.Author);

That's it, you've now created a references relationship between book and author. The foreign-key is assumed to be named Author_id in your book table, if that isn't to your liking you can use the Column method.

As with all other fluent mappings, you can chain calls to customise the reference relationship. For example if you wanted to specify the cascade strategy you'd use the Cascade property.

References(x => x.Author)
  .Column("AuthorId")
  .Cascade.All();

HasMany / one-to-many[]

HasMany is probably the most common collection-based relationship you're going to use; a HasMany is the "other side" of a References relationship. Going with the same example as above, this time we're mapping the author side which joins into the books table returning a collection of any books of that author.

public class Author
{
  public IList<Book> Books { get; set; }
}

To map this we use the HasMany method, as so:

HasMany(x => x.Books);

As with References, the foreign-key defaults to Author_id, and you can override it with the KeyColumn method.

There are a few different types of collections you can use, and they're all available under the HasMany call. You can read about them here.

HasManyToMany / many-to-many[]

HasManyToMany works exactly the same as #HasMany / one-to-many, except the underlying database structure it maps to is different.

HasManyToMany(x => x.Books);

There are a few different types of collections you can use, and they're all available under the HasManyToMany call. You can read about them here.

HasOne / one-to-one[]

HasOne is usually reserved for a special case, generally you'd use a References in most situations (see: I think you mean a many-to-one). If you really do want a one-to-one, then you can use the HasOne method.

HasOne(x => x.Cover);

Any[]

Any really only should be used if you know what you're doing. To quote the NHibernate documentation:

The <any> mapping element defines a polymorphic association to classes from multiple tables. This type of mapping always requires more than one column. The first column holds the type of the associated entity. The remaining columns hold the identifier. It is impossible to specify a foreign key constraint for this kind of association, so this is most certainly not meant as the usual way of mapping (polymorphic) associations. You should use this only in very special cases (eg. audit logs, user session data, etc).

There are three things you need to provide to be able to map using an Any; a column that holds the type of the entitiy, at least one column holding the identifier value, and a type for the identifier itself. You can specify these using the EntityTypeColumn, EntityIdentifierColumn, and IdentityType methods respectively.

ReferencesAny(x => x.Author)
  .EntityTypeColumn("Type")
  .EntityIdentifierColumn("Id")
  .IdentityType<int>();

Components[]

Components are a clever way of mapping a normalized data model into a more reasonable object model. You may have a customer table that has a series of address columns, ideally you'd want the address columns to be mapped into an Address object, rather than just being properties on a Customer; you can do that with components.

The Component method takes two parameters, rather than just one like the rest of the methods you've seen so far. The first parameter is a property accessor lambda, like all the other methods, and the second one is another lambda (quite often referred to as a nested-closure in these situations) that defines a new scope for defining the mappings of that particular sub-part (in this case the component).

Component(x => x.Address, m =>
{
  m.Map(x => x.Number);
  m.Map(x => x.Street);
  m.Map(x => x.PostCode);
});

As you can see, the first parameter references the Address property on our entity, which is the property that holds our component. The second property is where we define what makes up the component. The main difference in this lower scope is that you have to use the m instance to access the available methods; you don't have to call it m, but we are for brevity.

In this case we've mapped a component (stored in the Address property), that's made up of three properties (Number, Street, and PostCode); these properties are stored in the same table as the parent entity in a normalized fashion.

Subclasses[]

Subclasses work in a very similar way to ClassMap's, in that you create a derived class which you put your mappings in; it's just you use SubclassMap instead of ClassMap.

There are two strategies for mapping inheritance hierarchies in Fluent NHibernate, table-per-class-hierarchy and table-per-subclass; the former being a subclass, and the latter a joined-subclass.

Table-per-subclass is the default mapping for subclasses, so unless you say otherwise you'll have a separate table per-subclass. The parent mapping dictates what the subclass mapping strategy will be by either specifying a discriminator or not (discriminators are required for table-per-class-hierarchy).

We'll use the following two classes for examples:

public class Parent
{
  public int Id { get; set; }
  public string Name { get; set; }
}

public class Child : Parent
{
  public string AnotherProperty { get; set; }
}

If you wanted to map this as a table-per-subclass, you'd do it like this:

public class ParentMap : ClassMap<Parent>
{
  public ParentMap()
  {
    Id(x => x.Id);
    Map(x => x.Name);
  }
}

public class ChildMap : SubclassMap<Child>
{
  public ChildMap()
  {
    Map(x => x.AnotherProperty);
  }
}

That's all there is to it, parent and child are now mapped as subclasses. When Fluent NHibernate finds ChildMap it knows that it's a subclass of Parent.

If you wanted to do a table-per-class-hierarchy strategy, then you just need to specify the discriminator column in your ClassMap.

public class ParentMap : ClassMap<Parent>
{
  public ParentMap()
  {
    Id(x => x.Id);
    Map(x => x.Name);

    DiscriminateSubclassesOnColumn("type");
  }
}

public class ChildMap : SubclassMap<Child>
{
  public ChildMap()
  {
    Map(x => x.AnotherProperty);
  }
}

The only difference is in ParentMap we're now calling DiscriminateSubclassesOnColumn with a "type" parameter; this parameter is the column name in the table which dictates what class each row represents.