Fluent NHibernate Wiki
No edit summary
m (11 revisions: importing from original wiki)
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
  +
__TOC__
  +
 
Conventions are small self-contained chunks of behavior that are applied to the mappings Fluent NHibernate generates. These conventions are of varying degrees of granularity, and can be as simple or complex as you require. You should use conventions to avoid repetition in your mappings and to enforce a domain-wide standard consistency.
 
Conventions are small self-contained chunks of behavior that are applied to the mappings Fluent NHibernate generates. These conventions are of varying degrees of granularity, and can be as simple or complex as you require. You should use conventions to avoid repetition in your mappings and to enforce a domain-wide standard consistency.
   
The conventions are built using a set of interfaces and base classes that each define a single method, Apply, with varying parameters based on the kind of convention you're creating; this method is where you make the changes to the mappings.
+
The conventions are built using a [[Available conventions|set of interfaces and base classes]] that each define a single method, <code>Apply</code>, with varying parameters based on the kind of convention you're creating; this method is where you make the changes to the mappings.
   
By default conventions are applied before your mappings are created from the fluent mappings. What this means is you define the "shape" of your mappings first, then the conventions are applied to set all default values, and finally any explicit changes you made with the fluent mappings are applied.
+
By default conventions are applied before your mappings are created from the [[fluent mapping]]s. What this means is you define the "shape" of your mappings first, then the conventions are applied to set all default values, and finally any explicit changes you made with the fluent mappings are applied.
   
 
Given this mapping:
 
Given this mapping:
   
  +
<source lang="csharp">
public class PersonMap : ClassMap<Person>
+
public class PersonMap : ClassMap<Person>
{
+
{
public PersonMap()
+
public PersonMap()
{
+
{
Id(x => x.Id);
 
Map(x => x.Name);
+
Id(x => x.Id);
.Column("FullName")
+
Map(x => x.Name);
.Length(100);
+
.Column("FullName")
Map(x => x.Age);
+
.Length(100);
 
Map(x => x.Age);
}
 
}
+
}
 
}
  +
</source>
   
 
The convention workflow is:
 
The convention workflow is:
# Determine the shape of your mapping by looking at what high-level methods you called. With the PersonMap example, the shape is considered to be: ClassMap of Person, with an Id, and two Property's (Name and Age respectively); the Column and Length calls do not form a part of this shape and are purely value altering calls, these are ignored for the time being.
+
# Determine the shape of your mapping by looking at what high-level methods you called. With the <code>PersonMap</code> example, the shape is considered to be: ClassMap of Person, with an Id, and two Property's (Name and Age respectively); the Column and Length calls do not form a part of this shape and are purely value altering calls, these are ignored for the time being.
 
# Conventions are then applied to this shape, setting any values they wish; column names, lengths, cascades, access strategies, you name it.
 
# Conventions are then applied to this shape, setting any values they wish; column names, lengths, cascades, access strategies, you name it.
# Then the value altering methods from the fluent mappings are applied; in this case the Column and Length methods will then be applied.
+
# Then the value altering methods from the fluent mappings are applied; in this case the Column and Length methods will then be applied.
   
=Your first convention=
+
== Your first convention ==
   
One of the most common conventions you'll use is for classes, we'll start by using that as an example. class conventions are used to alter any value properties on the ClassMap<T> itself, if you wanted to alter specific properties or relationships you'd use their respective conventions from the available interfaces and base classes.
+
One of the most common conventions you'll use is for classes, we'll start by using that as an example. class conventions are used to alter any value properties on the <code>ClassMap<T></code> itself, if you wanted to alter specific properties or relationships you'd use their respective conventions from the [[Available conventions|available interfaces and base classes]].
   
  +
<source lang="csharp">
public class LowercaseTableNameConvention : IClassConvention
+
public class LowercaseTableNameConvention : IClassConvention
{
+
{
public void Apply(IClassInstance instance)
+
public void Apply(IClassInstance instance)
{
+
{
// alterations
+
// alterations
}
 
}
+
}
 
}
  +
</source>
   
That's an empty class convention! Lets make it do something useful. For a simple example we'll set a default table name for our entities; we'll simulate some daft archaic rule that all table names must be prefixed with tbl_.
+
That's an empty class convention! Lets make it do something useful. For a simple example we'll set a default table name for our entities; we'll simulate some daft archaic rule that all table names must be prefixed with <code>tbl_</code>.
   
  +
<source lang="csharp">
public void Apply(IClassInstance instance)
+
public void Apply(IClassInstance instance)
{
+
{
classMap.Table("tbl_" + classMap.Type.Name);
+
classMap.Table("tbl_" + classMap.Type.Name);
}
 
  +
}
  +
</source>
   
Simple. The IClassInstance interface contains several properties that allow you to inspect what has been set on the mapping, and usefully gives you access to the underlying System.Type that the mapping is using. We can then use that information to change the table name using the Table method.
+
''Simple.'' The <code>IClassInstance</code> interface contains several properties that allow you to inspect what has been set on the mapping, and usefully gives you access to the underlying <code>System.Type</code> that the mapping is using. We can then use that information to change the table name using the <code>Table</code> method.
==Conditional applying of conventions==
 
   
 
=== Conditional applying of conventions ===
See: Acceptance criteria
 
   
 
<blockquote>See: [[Acceptance criteria]]</blockquote>
Sometimes it may be necessary to control when a convention is applied; you may want a convention to only act on a subset of the mappings that it would normally alter. You can do this by implementing an additional interface that exposes an Accept method which allows you to define the criteria for which it will be applied.
 
   
 
Sometimes it may be necessary to control when a convention is applied; you may want a convention to only act on a subset of the mappings that it would normally alter. You can do this by implementing an additional interface that exposes an <code>Accept</code> method which allows you to define the criteria for which it will be applied.
The additional interface you need to implement has the same name as your main convention interface, with "Acceptance" on the end. So IClassConvention would have an IClassConventionAcceptance interface.
 
   
 
The additional interface you need to implement has the same name as your main convention interface, with "Acceptance" on the end. So <code>IClassConvention</code> would have an <code>IClassConventionAcceptance</code> interface.
public class LowercaseTableNameConvention : IClassConvention, IConventionAcceptance<IClassInspector>
 
{
 
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
 
{
 
// alterations
 
}
 
 
/* snip */
 
   
  +
<source lang="csharp">
The IAcceptanceCriteria instance is what you use to setup various expectations, for more information about the criterias you can create see: Acceptance criteria.
 
 
public class LowercaseTableNameConvention : IClassConvention, IConventionAcceptance<IClassInspector>
 
{
 
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
 
{
 
// alterations
 
}
   
 
/* snip */
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
 
  +
</source>
{
 
criteria.Expect(x => x.Type != typeof(SomeSpecialCase));
 
}
 
   
 
The <code>IAcceptanceCriteria</code> instance is what you use to setup various expectations, for more information about the criterias you can create see: [[Acceptance criteria]].
That example simply changes the convention so that it won't be applied to any mappings of the SomeSpecialCase type.
 
  +
  +
<source lang="csharp">
 
public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
 
{
 
criteria.Expect(x => x.Type != typeof(SomeSpecialCase));
  +
}
  +
</source>
  +
 
That example simply changes the convention so that it won't be applied to any mappings of the <code>SomeSpecialCase</code> type.
   
 
Not specifying any expectations is the same as not creating an Accept.
 
Not specifying any expectations is the same as not creating an Accept.
=Configuration=
 
   
 
== Configuration ==
Now that we've created our convention, we need to inform Fluent NHibernate of how to use it. The simplest way to do this is just to use the Fluent configuration mapping setup to use all conventions in an assembly, alternatively you can just add individual conventions. Both these are done through the Conventions property of the fluent mappings setup.
 
   
 
Now that we've created our convention, we need to inform Fluent NHibernate of how to use it. The simplest way to do this is just to use the [[Fluent configuration]] mapping setup to use all conventions in an assembly, alternatively you can just add individual conventions. Both these are done through the <code>Conventions</code> property of the fluent mappings setup.
Fluently.Configure()
 
.Database(/* database config */)
 
.Mappings(m =>
 
{
 
m.FluentMappings
 
.AddFromAssemblyOf<Entity>()
 
.Conventions.AddFromAssemblyOf<LowercaseTableNameConvention>();
 
})
 
   
  +
<source lang="csharp">
Alternatively you can use just Add to add an instance or a type, or you can use the Setup method to call a lambda that can be used to supply multiple different conventions (e.g. some from an assembly, and some individually).
 
 
Fluently.Configure()
 
.Database(/* database config */)
 
.Mappings(m =>
 
{
 
m.FluentMappings
 
.AddFromAssemblyOf<Entity>()
 
.Conventions.AddFromAssemblyOf<LowercaseTableNameConvention>();
 
})
  +
</source>
 
 
Alternatively you can use just <code>Add</code> to add an instance or a type, or you can use the <code>Setup</code> method to call a lambda that can be used to supply multiple different conventions (e.g. some from an assembly, and some individually).
   
 
Once you've set that up, Fluent NHibernate will automatically call your convention when it's generating the mappings.
 
Once you've set that up, Fluent NHibernate will automatically call your convention when it's generating the mappings.
 
=Note on previous conventions=
+
== Note on previous conventions ==
 
If you were using our previous conventions API, then you may be interested in converting to new style conventions, which explains the various differences you may encounter; however, there's nothing difficult about it, you just need to pick the right interface. If you're not quite comfortable with this change yet, the convention shortcuts might be of some use.
 
   
 
If you were using our previous conventions API, then you may be interested in [[converting to new style conventions]], which explains the various differences you may encounter; however, there's nothing difficult about it, you just need to [[Available conventions|pick the right interface]]. If you're not quite comfortable with this change yet, the [[convention shortcut]]s might be of some use.
Retrieved from "http://wiki.fluentnhibernate.org/Conventions"
 

Latest revision as of 11:24, 16 September 2009

Conventions are small self-contained chunks of behavior that are applied to the mappings Fluent NHibernate generates. These conventions are of varying degrees of granularity, and can be as simple or complex as you require. You should use conventions to avoid repetition in your mappings and to enforce a domain-wide standard consistency.

The conventions are built using a set of interfaces and base classes that each define a single method, Apply, with varying parameters based on the kind of convention you're creating; this method is where you make the changes to the mappings.

By default conventions are applied before your mappings are created from the fluent mappings. What this means is you define the "shape" of your mappings first, then the conventions are applied to set all default values, and finally any explicit changes you made with the fluent mappings are applied.

Given this mapping:

public class PersonMap : ClassMap<Person>
{
  public PersonMap()
  {
    Id(x => x.Id);
    Map(x => x.Name);
      .Column("FullName")
      .Length(100);
    Map(x => x.Age);
  }
}

The convention workflow is:

  1. Determine the shape of your mapping by looking at what high-level methods you called. With the PersonMap example, the shape is considered to be: ClassMap of Person, with an Id, and two Property's (Name and Age respectively); the Column and Length calls do not form a part of this shape and are purely value altering calls, these are ignored for the time being.
  2. Conventions are then applied to this shape, setting any values they wish; column names, lengths, cascades, access strategies, you name it.
  3. Then the value altering methods from the fluent mappings are applied; in this case the Column and Length methods will then be applied.

Your first convention[]

One of the most common conventions you'll use is for classes, we'll start by using that as an example. class conventions are used to alter any value properties on the ClassMap<T> itself, if you wanted to alter specific properties or relationships you'd use their respective conventions from the available interfaces and base classes.

public class LowercaseTableNameConvention : IClassConvention
{
  public void Apply(IClassInstance instance)
  {
    // alterations
  }
}

That's an empty class convention! Lets make it do something useful. For a simple example we'll set a default table name for our entities; we'll simulate some daft archaic rule that all table names must be prefixed with tbl_.

public void Apply(IClassInstance instance)
{
  classMap.Table("tbl_" + classMap.Type.Name);
}

Simple. The IClassInstance interface contains several properties that allow you to inspect what has been set on the mapping, and usefully gives you access to the underlying System.Type that the mapping is using. We can then use that information to change the table name using the Table method.

Conditional applying of conventions[]

See: Acceptance criteria

Sometimes it may be necessary to control when a convention is applied; you may want a convention to only act on a subset of the mappings that it would normally alter. You can do this by implementing an additional interface that exposes an Accept method which allows you to define the criteria for which it will be applied.

The additional interface you need to implement has the same name as your main convention interface, with "Acceptance" on the end. So IClassConvention would have an IClassConventionAcceptance interface.

public class LowercaseTableNameConvention : IClassConvention, IConventionAcceptance<IClassInspector>
{
  public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
  {
    // alterations
  }

  /* snip */

The IAcceptanceCriteria instance is what you use to setup various expectations, for more information about the criterias you can create see: Acceptance criteria.

public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
{
  criteria.Expect(x => x.Type != typeof(SomeSpecialCase));
}

That example simply changes the convention so that it won't be applied to any mappings of the SomeSpecialCase type.

Not specifying any expectations is the same as not creating an Accept.

Configuration[]

Now that we've created our convention, we need to inform Fluent NHibernate of how to use it. The simplest way to do this is just to use the Fluent configuration mapping setup to use all conventions in an assembly, alternatively you can just add individual conventions. Both these are done through the Conventions property of the fluent mappings setup.

Fluently.Configure()
  .Database(/* database config */)
  .Mappings(m =>
  {
    m.FluentMappings
      .AddFromAssemblyOf<Entity>()
      .Conventions.AddFromAssemblyOf<LowercaseTableNameConvention>();
  })

Alternatively you can use just Add to add an instance or a type, or you can use the Setup method to call a lambda that can be used to supply multiple different conventions (e.g. some from an assembly, and some individually).

Once you've set that up, Fluent NHibernate will automatically call your convention when it's generating the mappings.

Note on previous conventions[]

If you were using our previous conventions API, then you may be interested in converting to new style conventions, which explains the various differences you may encounter; however, there's nothing difficult about it, you just need to pick the right interface. If you're not quite comfortable with this change yet, the convention shortcuts might be of some use.