FANDOM



Fluent NHibernate has a concept called Auto Mapping, which is a mechanism for automatically mapping all your entities based on a set of conventions.

Auto mapping utilises the principal of convention over configuration. Using this principal, the auto mapper inspects your entities and makes assumptions of what particular properties should be. Perhaps you have a property with the name of Id and type of int, the auto mapping will decide that this is an auto-incrementing primary key.

By using the auto mappings, you can map your entire domain with very little code, and certainly no XML. There are still scenarios where it may not be suitable to use the auto mapping, at which point it would be more appropriate to use the ClassMap based fluent mappings; however, for most greenfield applications (and quite a few brownfield ones too) auto mapping will be more than capable.

Getting started Edit

Lets go through how to map a simple domain using the Fluent NHibernate AutoMapper.

Given the following clichéd store domain:

public class Product
{
  public virtual int Id { get; private set; }
  public virtual string Name { get; set; }
  public virtual decimal Price { get; set; }
}
 
public class Shelf
{
  public virtual int Id { get; private set; }
  public virtual IList<Product> Products { get; private set; }
 
  public Shelf()
  {
    Products = new List<Product>();
  }
}

We've got a product, with an auto-incrementing primary key called Id, and Name and Price properties. The store has some shelves it fills with products, so there's a Shelf entity, which has an Id, and a list of the Product's on it; the Product collection is a one-to-many or HasMany relationship to the Product.

I'm going to make the assumption here that you have an existing NHibernate infrastructure, if you don't then it's best you consult a general NHibernate walkthrough before continuing.

We're going to be using the AutoMap class to do our mapping, which you can use in combination with the fluent configuration API. To begin with we should take a look at the static AutoMap.AssemblyOf<T> method; this method takes a generic type parameter from which we determine which assembly to look in for mappable entities.

AutoMap.AssemblyOf<Product>();

That's it, you've mapped your domain. There are a few customisations you'll want to make before putting this into production though.

Lets go through what's actually happening here. The AutoMap.AssemblyOf<Product> call creates an instance of an AutoPersistenceModel that's tied to the assembly that Product is declared. No mappings are actually generated until we push them into NHibernate, this gives us opportunity to customise them before-hand, which we'll go into later.

We're going to utilise the fluent configuration API to create our SessionFactory.

var sessionFactory = Fluently.Configure()
  .Database(/* database config */)
  .Mappings(m =>
    m.AutoMappings
      .Add(AutoMap.AssemblyOf<Product>()))
  .BuildSessionFactory();

You can see that our AutoMap is sat in the middle of the configuration, inside the Mappings call; this is our way of telling Fluent NHibernate that we're using the auto mapper; there's nothing stopping you from passing in an instance of AutoPersistenceModel that you've configured elsewhere, we're just doing it in-line for brevity.

We're now capable of getting NHibernate to accept our auto mapped entities, there's just one more thing we need to deal with. The auto mapper doesn't know which classes are your entities, and which ones are everything else. The setup we're using above simply maps every class in your assembly as an entity, which isn't going to be very useful; so I'll introduce another method: Where(Func<Type, bool>).

The Where method takes a delegate which is used to limit types based on your own criteria. The most common usage is based on the namespace, but you could also look at the type name, or anything else exposed on the Type instance.

var autoMappings = AutoMap.AssemblyOf<Product>()
  .Where(t => t.Namespace == "Storefront.Entities");

Bringing all that together leaves us with this NHibernate setup:

var sessionFactory = Fluently.Configure()
  .Database(/* database config */)
  .Mappings(m =>
    m.AutoMappings.Add(
      AutoMap.AssemblyOf<Product>()
        .Where(t => t.Namespace == "Storefront.Entities")))
  .BuildSessionFactory();

Or if you prefer it separate:

var model = AutoMap.AssemblyOf<Product>()
  .Where(t => t.Namespace == "Storefront.Entities");
 
var sessionFactory = Fluently.Configure()
  .Database(/* database config */)
  .Mappings(m => m.AutoMappings.Add(model))
  .BuildSessionFactory();

That's all that you should need. It's all a lot easier than writing out mappings, isn't it?

Identities Edit

The automapper is opinionated, it expects your classes to be designed in a particular manner; if they're not, then it won't be able to automap them without a little assistance. The automapper expects your identities to be named Id, and if they aren't it won't find them.

You can modify the way the automapper discovers identities by using the FindIdentity setting. This setting is a lambda that is called with each property of each entity, you just need to return true for any property that matches your identity pattern.

.Setup(s =>
  s.FindIdentity =
    property => property.Name == property.DeclaringType.Name + "Id");

That example would match any ids that are named after their entity, such as CustomerId.

Components Edit

Sometimes you need components in your domain model, here's how to map them automatically.

Lets imagine this database structure:

TABLE Person (
  Id INT PRIMARY KEY,
  Name VARCHAR(200),
  AddressNumber INT,
  AddressStreet VARCHAR(100),
  AddressPostCode VARCHAR(8)
)

We want to map that to the following model:

public class Person
{
  public virtual int Id { get; private set; }
  public virtual string Name { get; set; }
  public virtual Address Address { get; set; }
}
 
public class Address
{
  public int Number { get; set; }
  public string Street { get; set; }
  public string PostCode { get; set; }
}

With this design Address is actually a component, which isn't a full entity, more of a way of providing a clean model to a normalised database structure. Lets start with what we left off with:

AutoMap.AssemblyOf<Person>()
  .Where(type => type.Namespace.EndsWith("Domain");

We've now got the auto mappings integrated with NHibernate, so we need to instruct the auto mapper how to identify components; after the Where call, we can add a call to WithSetup to help the auto mapper identify our components.

.Setup(s =>
{
  s.IsComponentType =
    type => type == typeof(Address);
})

The IsComponentType property we just set is what Fluent NHibernate uses to determine whether a type is one that will be mapped as a component.

It's fairly common that you'll have more than one convention type, you'll need to chain together ORs in your IsComponentType lambda, or check on something more generic like the namespace.

The Address should now be automatically mapped as a component; the auto mapper will pick up the three properties and map them as properties on the component.

If you need to customise the column naming of your component's properties you can set the GetComponentColumnPrefix property:

.Setup(s =>
{
  s.IsComponentType =
    type => type == typeof(Address);
  s.GetComponentColumnPrefix =
    type => type.Name + "_";
})

The convention now specifies that columns should be named TypeName_PropertyName, so Address.Street is now mapped to Address_Street.

Conventions Edit

The mappings produced by Fluent NHibernate are based on a pre-defined set of assumptions about your domain, this allows us to greatly reduce the amount of code you're required to write; sometimes however, the conventions we supply are not to your liking, perhaps you're a control-freak and want to have full say over your design, or more likely you're working against an existing database that has its own set of standards.

You'd still like to use the auto mapper, but can't because it maps your entities all wrong. Luckily for you we've thought about that, the auto mapper can utilise the conventions just like fluent mappings.

Using the following entities:

public class Product  
{  
  public int Id { get; private set; }  
  public virtual string Name { get; set; }  
  public virtual decimal Price { get; set; }  
}  
 
public class Shelf  
{  
  public virtual int Id { get; private set; }  
  public virtual IList<Product> Products { get; private set; }  
 
  public Shelf()
  {
    Products = new List<Product>();
  }
}

The standard conventions, it'd map to a database schema like this:

TABLE Product (
  Id INT IDENTITY PRIMARY KEY,
  Name VARCHAR(100),
  Price DECIMAL,
  Shelf_id INT FOREIGN KEY
)
 
TABLE Shelf (
  Id INT IDENTITY PRIMARY KEY
)

Nothing too complicated there, but that might not be the schema you expect. Lets pretend (or not!) that you name the primary key after the table it's in, so our Product identity should be called ProductId; also, you like your foreign key's to be explicitly named _FK, and your strings are always a bit longer than 100.

Remember this fellow?

AutoMap.AssemblyOf<Product>()  
  .Where(t => t.Namespace == "Storefront.Entities");

Lets update it to include some convention overrides. We'll start with the Id name. The conventions we're about to implement are better explained in the conventions page.

AutoMap.AssemblyOf<Product>()
  .Where(t => t.Namespace == "Storefront.Entities")
  .Conventions.Add<PrimaryKeyConvention>();

We've added a convention to the convention discovery mechanism, now let's implement it.

public class PrimaryKeyConvention
  : IIdConvention
{
  public void Apply(IIdentityInstance instance)
  {
    instance.Column(instance.EntityType.Name + "Id");
  }
}

Our PrimaryKeyConvention gets applied to all Ids and sets their column name based on the entity that contains the Id property. Our primary key's will now be generated as TypeNameId; which means our schema now looks like this:

TABLE Product (
  ProductId INT IDENTITY PRIMARY KEY,
  Name VARCHAR(100),
  Price DECIMAL,
  Shelf_id INT FOREIGN KEY
)
 
TABLE Shelf (
  ShelfId INT IDENTITY PRIMARY KEY
)

As you can see, our primary key's now have our desired naming convention. Lets do the other two together, as they're so simple; we'll override the foreign-key naming, and change the default length for strings.

.Conventions.Setup(c =>
{
  c.Add<PrimaryKeyConvention>();
  c.Add<CustomForeignKeyConvention>();
  c.Add<DefaultStringLengthConvention>();
});
 
public class CustomForeignKeyConvention
  : ForeignKeyConvention
{
  protected override string GetKeyName(PropertyInfo property, Type type)
  {
    if (property == null)
      return type.Name + "_FK";
 
    return property.Name + "_FK";
  }
}
 
public class DefaultStringLengthConvention
  : IPropertyConvention
{
  public void Apply(IPropertyInstance instance)
  {
    instance.Length(250);
  }
}

That's all there is to it, when combined with the other conventions you can customise the mappings quite heavily while only adding a few lines to your auto mapping.

This is our final schema:

TABLE Product (
  ProductId INT IDENTITY PRIMARY KEY,
  Name VARCHAR(250),
  Price DECIMAL,
  Shelf_FK INT FOREIGN KEY
)
 
TABLE Shelf (
  ShelfId INT IDENTITY PRIMARY KEY
)

Altering entities Edit

Sometimes it's necessary to make slight changes to a specific entity, without wishing to affect anything else; you can do that with the with Override<T> method.

.Override<Shelf>(map =>
{
  map.HasMany(x => x.Products)
    .Cascade.All();
});

The Override method takes a generic parameter that's the entity you want to customise. The parameter is an expression that allows you to alter the underlying mapping that is generated by the auto mapper. You can do just about anything in this call that you can do in the fluent mappings.

In the example above we're setting Cascade.All on the HasMany of Products for the entity Shelf.

You can do this for as many types as you need in your domain; however, baring in mind readability, it may sometimes be more appropriate to use an override or map entities explicitly using the fluent mappings if you find yourself overriding a lot of conventions.

Overrides Edit

Using too many calls to Override can quickly clutter up your auto mapping setup; an alternative is to use an IAutoMappingOverride<T>, which is an interface you can implement to override the mappings of a particular auto-mapped class.

public class PersonMappingOverride
  : IAutoMappingOverride<Person>
{
  public void Override(AutoMap<Person> mapping)
  {
  }
}

This example overrides the auto-mapping of a Person entity. Within the Override method you can perform any actions on the mapping that you can in the fluent mappings.

To use overrides, you need to instruct your AutoMap instance to use them. Typically this would be done in the context of a fluent configuration setup, but I'll just illustrate with the AutoMap on it's own.

AutoMap.AssemblyOf<Person>()
  .Where(type => type.Namespace == "Entities")
  .UseOverridesFromAssemblyOf<PersonMappingOverride>();

It's the UserOverridesFromAssemblyOf<T> call that instructs the AutoPersistenceModel to read any overrides that reside the assembly that contains T.

Ignoring properties Edit

When using the auto mapper sometimes you may want to ignore certain properties on your entity. If it's only for one entity, then you can override the entity or specify an alteration each which allow you to call an IgnoreProperty method.

For example:

.Override<Shelf>(map =>  
{  
  map.IgnoreProperty(x => x.YourProperty);
});

If you need to ignore a property regardless of what type it's present on, you can use the OverrideAll method, which exposes a similar interface.

.OverrideAll(map =>  
{  
  map.IgnoreProperty("YourProperty");
});

The difference in this case is that because we don't know the entity at the time of writing our ignore call, we have to specify the name with a string; this is not ideal, but there aren't really any alternatives in this situation.

There are a couple of overloads available when using OverrideAll.

A single property:

.OverrideAll(map =>  
{  
  map.IgnoreProperty("YourProperty");
});

Multiple properties:

.OverrideAll(map =>  
{  
  map.IgnoreProperties("YourProperty", "AnotherProperty");
});

Properties by predicate:

.OverrideAll(map =>  
{  
  map.IgnoreProperties(x => x.Name.Contains("Something"));
});

That last one is powerful. You can do whatever you like in that predicate against the PropertyInfo instance supplied. You could check if the name contains a particular string, like above, or you could check if the property has a particular attribute on.

Inheritance Edit

There are two main things that you'd want to do with inherited classes, either ignore the base class all together, or map them using an inheritance strategy. I'm going to start with the former, then move on to the latter.

Ignoring base-types Edit

This scenario is where you may have a base class in your domain that you use to simplify your entities, you've moved common properties into it so you don't have to recreate them on every entity; typically this would be the Id and perhaps some audit information. So lets start with a model that has a base class we'd like to ignore.

namespace Entities
{
  public abstract class Entity
  {
    public virtual int Id { get; set; }    
  }
 
  public class Person : Entity
  {
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
  }
 
  public class Animal : Entity
  {
    public virtual string Species { get; set; }
  }
}

Relatively simple model here, we've got an Entity base class that defines the Id, then the Person and Animal entities. We have no desire to have Entity mapped by NHibernate, so we need a way to tell the auto mapper to ignore it.

For those individuals from traditional XML mapping land, this is what we're going to be recreating:

<class name="Person">
  <id name="Id">
    <generator class="identity" />
  </id>
 
  <property name="FirstName" />
  <property name="LastName" />
</class>
 
<class name="Animal">
  <id name="Id">
    <generator class="identity" />
  </id>
 
  <property name="Species" />
</class>

We'll start with this automapping setup:

AutoMap.AssemblyOf<Entity>
  .Where(t => t.Namespace == "Entities");

If we were to run this now, we wouldn't get the mapping we desire. Fluent NHibernate would see Entity as an actual entity and map it with Animal and Person as subclasses; this is not what we desire, so we need to modify our auto mapping configuration to reflect that.

After AutoMap.AssemblyOf<Entity>() we need to alter the conventions that the auto mapper is using so it can identify our base-class.

AutoMap.AssemblyOf<Entity>()
  .IgnoreBase<Entity>()
  .Where(t => t.Namespace == "Entities");

We've added the IgnoreBase<Entity> call which simply instructs the automapper to ignore the Entity class; you can chain this call as many times as needed.

With this change, we now get our desired mapping. Entity is ignored as far is Fluent NHibernate is concerned, and all the properties (Id in our case) are treated as if they were on the specific subclasses.

Base-type as an inheritance strategy Edit

If you want to have your base-class included in NHibernate, then just don't include the IgnoreBase above! Easy.

Configuring the subclassing strategy Edit

Fluent NHibernate defaults to using table-per-subclass strategy for automapping inheritance hierarchies. If this is not what you want, then you can configure it using the SubclassStrategy configuration option.

If you just want every hierarchy to be mapped using the same strategy, then you'd use SubclassStrategy like so:

AutoMap.AssemblyOf<Entity>()
  .Setup(s =>
  {
    s.SubclassStrategy = t => SubclassStrategy.Subclass;
  });

However, if you wanted to customise it on a per-class basis, you'd set it up like so:

AutoMap.AssemblyOf<Entity>()
  .Setup(s =>
  {
    s.SubclassStrategy = t => t == typeof(ClassOne) || typeof(ClassTwo);
  });

Subclassing FAQs Edit

Abstract base-classes Edit

You'll notice that our Entity class is abstract. This is good practice, but for the record, it is not mandatory. If you're experiencing problems, it's unlikely to be this.

In case you're wondering, making the class abstract is like saying "I'll never create an Entity directly, instead I will create derived classes such as Customer and Order (which inherit from Entity)."

The default behavior is to consider abstract classes as layer supertypes and effectively unmapped, you may want to change this for specific scenarios. The easiest way to do this is to use IncludeBase<T>, where T is your entity.

AutoMap.AssemblyOf<Entity>()
  .IncludeBase<AbstractBaseClass>();

This forces the automapper to include that base-type, regardless of it's previous assumptions about it.

Protected setters Edit

Sometimes you only want your class to be able to set it's own properties, not the outside world. For example, the Id and CreatedAt properties might never need to be set anywhere but in the class itself.

public abstract Entity
{
    public virtual int Id {get; protected set;}
    public virtual DateTime CreatedAt { get; protected set;}
 
    public Entity()
    {
       CreatedAt = DateTime.Now;
    }
}

Be sure to make these setters protected rather than private. Doing this will ensure they are included in the Auto Mappings.

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.