Showing posts with label Fluent NHibernate. Show all posts
Showing posts with label Fluent NHibernate. Show all posts

Friday, February 17, 2012

Mapping-by-Code & Fluent NHibernate issues summary

In my mapping-by-code posts series I've just completed, I reviewed the capabilities of both mapping-by-code and Fluent NHibernate in comparison to plain old XML mappings. There are some more or less serious bugs on both sides, as well as both solutions don't offer everything XML does. In each case, when I found the issue worth mentioning, I was looking if it was already reported and reported it myself if not. Here is the quick summary:

Mapping-by-Code

Fluent NHibernate


As you can see, the number of issues I've encountered is very similiar for both mapping-by-code and Fluent NHibernate. For mapping-by-code, majority of them were already reported and actions were taken. Actually, 5 of them are already resolved and wait for NH 3.3 release. I've reported 3 new issues (one of which was fixed in few days) and extended another one.

For Fluent NHibernate, I've reported 8 issues out of 10 encountered. Sadly, by now, none of them were even commented. It looks like there's no active development on FNH. I tend to agree that leaving issues in no man's land with no status at all is a sign of a neglected community. I'd prefer to have these issues closed with "won't do" status than ignored, for sure.

Wednesday, February 15, 2012

NHibernate's mapping-by-code - the summary

Six weeks ago, when I started my experiments with NHibernate's 3.2 new mapping feature - mapping-by-code, I was a loyal Fluent NHibernate user and a fan of method chains in APIs. My first impression about mapping-by-code was that it seems to be a good direction, but it's still immature and - what's important - not documented at all. I decided to have a deeper look and it turned into almost twenty parts series exploring all the possible mappings - probably the only complete guide to mapping-by-code on the web so far. Time to sum the series up.

Let's start with what mapping-by-code is. It is an XML-less mapping solution being an integral part of NHibernate since 3.2, based on ConfORM library. Its API tries to conform to XML naming and structure. There's a strong convention in how the mapping methods are built. Its names are almost always equal to XML elements names. The first parameter points to the mapped property, second is for its options corresponding XML attributes (and XML <key> element, if applicable) and the rest of parameters, if any, corresponds to nested XML elements. It's very convenient for those familiar with XML schema or for documentation readers.

Mapping-by-code also came with very powerful mapping by convention tool - ConventionModelMapper. It is highly flexible and customizable, but customizing it may not even be needed, as by default it is able to figure out mappings even for components or maps. The only thing it can't map automatically are bidirectional relationships - but it was pretty easy to fix this using conventions (I've updated my conventions since first published - it now supports all kinds of collections, inheritance and more - feel free to use it).

Here is the full table of contents of my mapping-by-code series.

  1. First impressions
  2. Naming convention resembling Fluent
  3. Property
  4. Component
  5. ManyToOne
  6. inheritance
  7. dynamic component
  8. Set and Bag
  9. OneToMany and other collection-based relation types
  10. concurrency
  11. OneToOne
  12. Join
  13. Any
  14. List, Array, IdBag
  15. Map
  16. Id, NaturalId
  17. composite identifiers
  18. entity-level mappings

And what about Fluent NHibernate? Hiding the XML was a great idea, but simplifying the mappings went too far, in my opinion. I've already mentioned the mess caused by concept name changes made in Fluent NHibernate (1) (2) - I wouldn't repeat it again. Moreover, XML mapping is a tree structure and it just doesn't fit into single method chains. Fluent NHibernate's API bypasses this limitations by prefixing method names (like KeyColumn) or by falling back to the interface that uses Action<T> (i.e. in Join or Component mapping), quite similiar to mapping-by-code API. Method chaining also makes it hard to reuse the same concepts in different contexts. It's lot easier in mapping-by-code way - i.e. Column mapping is the same in every mapped feature and it is handled by exactly the same code.

Don't get me wrong. I think FNH was a good and useful project. But I've used it as the only existing alternative to cumbersome and verbose XML mapping. And now, when we have an alternative that is integrated into NHibernate (no external dependency and versioning issues), more efficient (no XML serialization) and with better API (no ambiguity, NH naming kept), the purpose of FNH's existence is highly reduced.

Monday, February 13, 2012

Mapping-by-Code - entity-level mappings

We're finally reaching the end of mapping-by-code series. In the last post about mapping possibilities I will cover all options mapped directly at the entity level, that do not map to a column in the database. They define different entity behaviors and customization options and majority of them translates to elements or attributes in XML <class> mapping. Let's go through these possibilities.

Table("tableName");
Schema("schemaName");
Catalog("catalogName");

These are pretty obvious ones - they define where in the database the entity is represented.

EntityName("entityName");
DynamicInsert(true);
DynamicUpdate(true);
BatchSize(10);
Lazy(true);
SelectBeforeUpdate(true);
Mutable(true);
Synchronize("table1", "table2");
SchemaAction(NHibernate.Mapping.ByCode.SchemaAction.All); // or .Drop, .Export, .None, .Update, .Validate
  • EntityName allows to define an alias for the entity - useful when we're mapping the same class more than once.
  • DynamicInsert and DynamicUpdate decide whether to restrict constructed SQL queries only to properties modified explicitly (by default - with these options turned off - NHibernate inserts/updates all properties everytime).
  • BatchSize is an last resort solution for Select N+1 problem - it sets up batching when loading entities in a loop.
  • Lazy(false) completely turns off lazy loading for the entity (no proxy is created).
  • SelectBeforeUpdate is to fetch the data before update, surprisingly - another way of dealing with concurrency.
  • Mutable(false) reduces the NHibernate's infrastructure when the entity is read-only for our application (i.e. when mapped to a database view or to a lookup-only table).
  • Synchronize informs NHibernate that the entity is derived from another and it should care not to return stale data when querying the derived entity.
  • SchemaAction is for hbm2ddl tool to decide what should it do when creating session factory.
Cache(c =>
{
c.Usage(CacheUsage.NonstrictReadWrite); // or .ReadOnly, .ReadWrite, .Transactional
c.Include(CacheInclude.All); // or .NonLazy
c.Region("regionName");
});

Cache is for second-level caching. We need to turn it on explicitly for every entity we want to cache by defining Usage model at least.

Filter("filterName", f => f.Condition("filter SQL condition"));
Where("SQL condition");

Filter and Where are two different ways of narrowing the scope of entities loaded and managed by NHibernate.

SqlInsert("custom SQL");
SqlUpdate("custom SQL");
SqlDelete("custom SQL");
Subselect("custom SQL");

These four are for customizing CRUD operations on the entity. Useful i.e. when access to the table should be done through the stored procedures only.

Loader("loaderReference");
Persister<CustomPersister>();
Proxy(typeof(ProxyType));

And these three are even more low-level possibilities for customization. Haven't explored it thoroughly, but I don't think there are lot of scenarios when they are needed.

There are some XML attributes that do not have an equivalent in mapping-by-code yet. These are tuplizer, resultset, abstract, polymorphism, optimistic-lock, check, rowid, node and import. Apart from optimistic-lock, they don't look important.

Fluent NHibernate's equivalents

FNH offers a bit different subset of entity-level options. Some of mapping-by-code deficiencies are covered (like OptimisticLock, Polymorphism, ImportType, CheckConstraint, Tuplizer), some features are missing instead (like Catalog, Synchronize, Loader). Here are the options available:

Table("tableName");
Schema("schemaName");

EntityName("entityName");
DynamicInsert();
DynamicUpdate();
BatchSize(10);
LazyLoad();
OptimisticLock.All(); // or .Dirty, .None, .Version
SelectBeforeUpdate();
ReadOnly();
Polymorphism.Explicit(); // or .Implicit
SchemaAction.All(); // or .Drop, .Export, .Update, .Validate, .Custom

Cache.IncludeAll() // or .IncludeNonLazy
.Region("regionName")
.NonStrictReadWrite(); // or .ReadOnly, .ReadWrite, .Transactional, .CustomUsage<>

ApplyFilter("filterName", "SQL condition");
Where("SQL condition");

CheckConstraint("check");
ImportType<Import>().As("alternativeName");

SqlInsert("sql query").Check.None(); // or .RowCount
SqlUpdate("sql query");
SqlDelete("sql query");
SqlDeleteAll("sql query");
Subselect("sql query");
StoredProcedure("command", "sql query").Check.None();

Persister<CustomPersister>();
Proxy(typeof(ProxyType));
Tuplizer(TuplizerMode.Xml, typeof(Tuplizer));

There are some name changes when compared to XML attributes or elements names. LazyLoad is for lazy, CheckConstraint for check, ReadOnly for mutable="false" and ApplyFilter covers filter element. StoredProcedure is used internally within SqlXYZ elements - I don't know why this method is in public API. There is also one elements that should not be there - SqlDeleteAll do not have an equivalent in XML mapping and can't be used.


And that's all for mappings exploration! I'll probably summarize the series in a separate post or two.

Friday, February 10, 2012

Mapping-by-Code - composite identifiers

Recently we've talked about surrogate primary keys. Let's move on to different foreign key types supported by NHibernate. We have composite keys available in two different ways, depending on whether we have the key represented in object model as a component (ComponentAsId) or just as several properties in the entity (ComposedId).

ComponentAsId(x => x.Key, m =>
{
m.Property(x => x.KeyPart);
// etc.
});

ComposedId(m =>
{
m.Property(x => x.KeyPart);
// other key parts
});

ComponentAsId is an equivalent of <composite-id> XML element with name and class attributes. ComposedId is an equivalent of <composite-id> without attributes. Both in ComponentAsId and ComposedId we need to specify properties taking part in the key and we do it in a standard way, known i.e. from Component mapping. In both cases a way to specify unsaved-value and mapped attributes is missing.

ComponentAsId is unfortunately broken in NHibernate 3.2 - it ignores the property name pointing to key component. It will be fixed in 3.3, in the meantime we have to use XML mapping here or modify the HbmMapping class directly, like this:

mapping.RootClasses.Single(x => x.Name == typeof(EntityWithComponentAsId).Name).CompositeId.name = "Key";

Fluent NHibernate's equivalents

Composite identifiers are supported well, too, in both variants.

// ComposedId equivalent
CompositeId()
.KeyProperty(x => x.KeyPart)
.KeyReference(x => x.KeyReference)
.UnsavedValue("string?")
.Access.Field();

// ComponentAsId equivalent
CompositeId(x => x.Key)
.KeyProperty(k => k.KeyPart)
.KeyReference(k => k.KeyReference)
.Not.Mapped()
.UnsavedValue("string?")
.Access.Field();

We have KeyProperty as an equivalent of key-property element in XML (mapped with Property in mapping-by-code). We have KeyReference for key-many-to-one (mapped with ManyToOne in mapping-by-code). We have Mapped method as an direct equivalent of mapped attribute from XML as well as UnsavedValue method for unsaved-value attribute (but why it is string-typed?).

There's also one more method in chain - ComponentCompositeIdentifier. It seems to be an alternative syntax for ComponentAsId case, but I couldn't make it produce valid XML mapping and the functionality is already covered, so I'll ignore it.

Wednesday, February 8, 2012

Mapping-by-Code - Id, NaturalId

I've already finished going through all the Ayende's posts about NHibernate mappings and analysing its mapping-by-code equivalents, but I feel I haven't covered everything. The first quite obvious NHibernate's feature Ayende skipped is primary key mapping. There are several options available - from identity columns, native generators, through HiLo and sequences, up to composite identifiers. As always, I'm not going to explain how each of them works, I'll keep focus on mapping-by-code and Fluent NHibernate's possibilities.

The most common primary key mapping is available through Id method.

Id(x => x.Id, m =>
{
m.Column("id");

m.Generator(Generators.Native, g => g.Params(new
{
// generator-specific options
}));

m.Length(10);
m.Type(new Int32Type());
m.Access(Accessor.Field);
});

There are several features missing - like unsaved-value (will be added in NHibernate 3.3) or DDL column options.

Probably the most important option is Generator. It specifies the way NHibernate (or database) generates unique values. There are 8 predefined types of generators available through static Generators class:

public static class Generators
{
// assigning the values is client code responsibility
public static IGeneratorDef Assigned { get; }

// whatever is native in underlying database
public static IGeneratorDef Native { get; }

// High-Low
public static IGeneratorDef HighLow { get; }

// Guid
public static IGeneratorDef Guid { get; }

// sequential Guid
public static IGeneratorDef GuidComb { get; }

// database-level sequence
public static IGeneratorDef Sequence { get; }

// database-level identity
public static IGeneratorDef Identity { get; }

// driven by referenced entity
public static IGeneratorDef Foreign<TEntity>(Expression<Func<TEntity, object>> property);
public static IGeneratorDef Foreign(MemberInfo property);
}

Some of those can have additional parameters specified using Generator method second parameter and anonymous type inside Params call. This is probably the only place in mapping-by-code when we have not strongly-typed options, but it's not worse than in XML.

Here are the parameters available for HighLow, as well as its default values:

m.Generator(Generators.HighLow, g => g.Params(new
{
max_lo = Int16.MaxValue, // size of ids range reserved at once - Int16.MaxValue by default
table = "hibernate_unique_key",
schema = null,
catalog = null,
column = "next_hi",
where = "", // additional SQL condition applied to query when fetching next_hi value
}));

And here is the similiar list for Sequence:

m.Generator(Generators.Sequence, g => g.Params(new
{
sequence = "hibernate_sequence",
schema = null,
catalog = null,
parameters = null, // driver-specific DDL string to be appended to create command
}));

There's another id-related option available - natural ID. It is in fact not a primary key handling option, but it's related, so I decided to include it here. It is available through NaturalId mapping method.

NaturalId(m =>
{
m.Property(x => x.KeyPropery);
// etc...
});

Mutable attribute from XML natural-id element has no equivalent in mapping-by-code.

Fluent NHibernate's equivalents

For mapping surrogate keys there is Id method chain available. Let's see first which of the generators are available directly:

Id(x => x.Id)
.GeneratedBy.Assigned()
.GeneratedBy.Custom<CustomGenerator>()
.GeneratedBy.Foreign("propertyName")
.GeneratedBy.Guid()
.GeneratedBy.GuidComb()
.GeneratedBy.GuidNative()
.GeneratedBy.HiLo("table", "column", "maxLo", "where")
.GeneratedBy.Identity()
.GeneratedBy.Increment()
.GeneratedBy.Native("sequenceName")
.GeneratedBy.Select()
.GeneratedBy.SeqHiLo("sequenceName", "maxLo")
.GeneratedBy.Sequence("sequenceName")
.GeneratedBy.SequenceIdentity("sequenceName")
.GeneratedBy.TriggerIdentity()
.GeneratedBy.UuidHex("format")
.GeneratedBy.UuidString();

All the parameters are optional. Apart from that, there is an additional configuration interface available in most generators:

p => p.AddParam("name", "value")

As we can see, the number of options available directly is higher than in mapping-by-code.

Time to look at different id mapping options.

Id(x => x.Id)
.Column("id")
.Length(10)
.CustomType<CustomType>()
.Access.Field()
.UnsavedValue(0)
.Check("sql constraint")
.CustomSqlType("sqlType")
.Default(0)
.Index("idx")
.Nullable()
.Precision(10)
.Scale(10)
.Unique()
.UniqueKey("uniq");

There are a lot more options available in FNH than in mapping-by-code. I think that at least some of them are completely useless (like defining unique key name), but this is not a FNH's bug, this is what NHibernate mapping does allow, surprisingly.

NaturalId is supported well, too.

NaturalId()
.Property(x => x.Name, "columnName")
.Reference(x => x.Test, "referenceColumnName")
// etc.
.Not.ReadOnly();

Column names are optional. There's no way to set other column options. And ReadOnly is FNH name for mutable attribute.

Monday, February 6, 2012

Mapping-by-Code - Map

The last not yet covered collection type supported in NHibernate 3.2 mapping-by-code is Map. I'll skip all the options that are common with set and bag and refer to its own post. For other collection types, see also the previous post.

Map is NHibernate's name for dictionary, or key-value collection. It is quite a powerful feature. NHibernate allows keys and values to be of different types - either single elements (like strings), components or entities. We can have an entity in the key and string in the value or string in the key and component in the value, etc. Moreover, as with every other collection, map can take part in one-to-many, many-to-many and even many-to-any relationships. There's quite a lot of options.

Mapping for all of these options must be scary, one may think. But not with mapping-by-code. I'm really impressed how easy, convenient and consistent with all the other features the Map mapping is. There's an recurring pattern in mapping-by-code that each nested element in XML has its corresponding options as a separate method parameter. And that's the case for Map, too. There are three basic overloads for Map method:

public void Map<TKey, TElement>(
Expression<Func<TEntity, IDictionary<TKey, TElement>>> property,
Action<IMapPropertiesMapper<TEntity, TKey, TElement>> collectionMapping);

public void Map<TKey, TElement>(
Expression<Func<TEntity, IDictionary<TKey, TElement>>> property,
Action<IMapPropertiesMapper<TEntity, TKey, TElement>> collectionMapping,
Action<ICollectionElementRelation<TElement>> mapping);

public void Map<TKey, TElement>(
Expression<Func<TEntity, IDictionary<TKey, TElement>>> property,
Action<IMapPropertiesMapper<TEntity, TKey, TElement>> collectionMapping,
Action<IMapKeyRelation<TKey>> keyMapping,
Action<ICollectionElementRelation<TElement>> mapping);

Don't be scared. These are just three variants of the same method ordered from the simplest one (with two parameters skipped - it'll have its default values) to the most complete one (with all four parameters). Let's focus on the last one.

The first parameter is - as always - the lambda expression pointing to a generic IDictionary property we are mapping. The second is an obligatory collection mapping - all the standard collection options (described in the post about Bag and Set) are available there. The third one, optional, is to set options for dictionary key mapping and the last one, also optional, is about its value mapping. Here it is, with all its options:

Map(x => x.Features, c =>
{
// standard collection options here
}, k =>
{
k.Element(e =>
{
e.Column("indexColumnName");
// or
e.Column(c =>
{
c.Name("indexColumnName");
// etc...
});

e.Formula("arbitrary SQL expression");
e.Length(10);
e.Type<CustomType>();
});
// or
k.Component(e =>
{
e.Property(x => x.KeyElement);
e.ManyToOne(x => x.OtherKeyElement);
// etc...
});
// or
k.ManyToMany(e =>
{
e.Column("indexColumnName");
// or
e.Column(c =>
{
c.Name("indexColumnName");
// etc...
});

e.ForeignKey("foreignKeyName");
e.Formula("arbitrary SQL expression");
});
}, r =>
{
// one of the following:
r.OneToMany();
r.Element();
r.Component(m => {});
r.ManyToMany();
r.ManyToAny<CommonIdType>(m => {});
});

Let's talk about key and value mappings (third and fourth parameter). In XML, there are plenty of different names for all its options, like map-key, composite-map-key, map-key-many-to-many etc. Mapping-by-code simplifies it drastically. We just need to choose what type of element our key is - either Element (for simple values), Component or ManyToMany (for cases when we have an entity as a key). We are already familiar with all the options inside. The same is for value mapping - we need to choose one of five possible relation types, depending on what do we have as a value in our dictionary. For the description of different relation types, see separate post - all the options are available here, too.

Moreover, the default ConventionModelMapper is smart enough to figure out most options just by looking at our model and in most cases we just don't need to specify the relation types and its options at all.

Fluent NHibernate's equivalent

In Fluent NHibernate, the name "Map" was already used for Property mapping. Instead we have several different methods in HasMany/HasManyToMany chains to be used - AsMap, AsEntityMap, AsSimpleAssociation, AsTernaryAssociation. Pretty hard to figure out what's what.

Mapping for the dictionary value and its options stays the same as in Bag/Set case. I'll focus on mapping different key types.

The first case is when we have simple value as a key - like IDictionary<string, string>:

HasMany(x => x.Dictionary)
.AsMap<string>("keyColumn")
.Element("valueColumn");

Majority of AsMap overloads want me to specify lambda expression pointing from the value to the key and internally use AsIndexedCollection method (designed for List, I believe). These methods seems to assume that key is a part of an object in value, what is strange a bit. In that case we don't really need to have a dictionary and we could just map that collection as a simple bag.

Moreover, FNH is not trying to determine the key type on its own - we need to specify it as a generic parameter in AsMap method explicitly, otherwise we'll end up with int. I also can't see the way to set other key options available in mapping-by-code, i.e. Length or Formula.

The second case I've tried was having a component as a key - and I've failed. I was looking through the Web and the source code itself and I can't see no composite-index equivalent.

Third type of objects allowed as a key is another entity - i.e. IDictionary<Entity, string>. We can map it using AsEntityMap:

HasMany(x => x.Dictionary)
.AsEntityMap()
.Element("valueColumn");

I was looking for any clues when should I use AsTernaryAssociation or AsSimpleAssociation directly, but I don't find any.

To sum things up, dictionary mapping in Fluent NHibernate is a horrible mess. I've found a comment in FNH source code: "I'm not proud of this. The fluent interface for maps really needs to be rethought. But I've let maps sit unsupported for way too long so a hack is better than nothing." Well, personally I'm not sure whether it'll be better in this case. Mapping by code is way much better this time.

Friday, February 3, 2012

Mapping-by-Code - List, Array, IdBag

Time to complete the subject of collection mappings - there are some features unique for lists and idbags that need to be mentioned. I'll skip all the options that are common with set and bag and refer to its own post.

List is an explicitly ordered collection. It has an additional option in the mapping for the index column that keeps the ordering, with the standard Column options mapping inside.

List(x => x.Districts, c =>
{
c.Index(idx =>
{
idx.Base(1);
idx.Column("indexColumnName");
// or
idx.Column(ic =>
{
ic.Name("indexColumnName");
// etc...
});
});
});

There are two other rarely used ordered collections in NHibernate - arrays and primitive arrays. Both are not supported in mapping-by-code. But I don't think it's a big deal.

Another collection type is IdBag. It is generally a bag enriched with additional identity column - useful for many-to-many intermediate tables, when we don't want to have composite primary key there. The only new option in the mapping is Id method, with several options available:

IdBag(x => x.Collection, c =>
{
c.Id(i =>
{
i.Column("idColumn");
i.Generator(Generators.Native);
i.Length(100);
i.Type(new Int32Type());
});
}, r => r.ManyToMany());

Fluent NHibernate's equivalents

As we already know, FNH defines collection mappings as a part of relation mapping chain. I'll skip all the options already covered in the Bag/Set post.

List is mapped using AsList method. There is a possibility to set index column name and type - other DDL options, as well as base attribute are missing.

HasMany(x => x.Users)
.AsList(idx => idx.Column("indexColumnName").Type<int>())

Array is also supported, contrary to mapping-by-code. It has similiar possibilities to the list mapping, the only difference is that we can define index column name by lambda parameter, but it's used only if we don't specify it in the second parameter explicitly.

HasMany(x => x.Users)
.AsArray(x => x.Name, idx => idx.Column("indexColumnName").Type<string>())

Primitive arrays and idbags are not supported.

Thursday, February 2, 2012

Mapping-by-Code - Any

Probably the last relation type supported by NHibernate we have left is any relationship. It is quite an exotic feature. Let's re-use Ayende's model again:

Any lets us to map many-to-one relationship that has entities of different types on the "one" side. There's no foreign keys defined on the database side and the relation logic is maintained on the object level only. To make it work, we need to tell NHibernate what types of entities we expect and how to distinguish it. Here's how to do it in mapping-by-code, with all the options available:

Any(x => x.Payment, typeof(long), m =>
{
m.IdType<long>();
m.MetaType<string>();
m.MetaValue("CreditCard", typeof(CreditCardPayment));
m.MetaValue("Wire", typeof(WirePayment));

m.Columns(id =>
{
id.Name("PaymentId");
id.NotNullable(true);
// etc...
}, classRef =>
{
classRef.Name("PaymentType");
classRef.NotNullable(true);
// etc...
});

m.Access(Accessor.Field);
m.Lazy(true);
m.Cascade(Cascade.Persist);
m.Index("payment_idx");
m.Insert(true);
m.Update(true);
m.OptimisticLock(true);
});

The first parameter is - as always - a lambda pointing to the mapped property. The second defines the common type for identifiers of all entities at the other side. Third one is for mapping options, which are pretty similiar to already mentioned ManyToAny relationship.

Inside the configuration we need to define properties for two columns - one to keep the other entity identifier, second to keep its discriminating value. We do it using Columns method's parameters. Later we have to specify the type of discriminator using MetaType method and its generic argument - string is good here. We can also specify the common type of identifiers using IdType method, but we've already did it in Any second parameter (I think that this method is useless here). The last thing we need to do is to define the list of entity types that are allowed at other side of the relation and its corresponding discriminator values. In order to do this, we call MetaValue method - its first parameter is the discriminator value, second is the type. There are also several standard options available, like Lazy and Cascade.

Fluent NHibernate's equivalent

Contrary to many-to-any, any is supported well in Fluent NHibernate.

ReferencesAny(x => x.Test)
.IdentityType<long>()
.MetaType<string>()
.AddMetaValue<CreditCardPayment>("CreditCard")
.AddMetaValue<WirePayment>("Wire")
.EntityIdentifierColumn("PaymentId")
.EntityTypeColumn("PaymentType")
.Access.Field()
.LazyLoad()
.Cascade.All()
.Insert()
.Update()
.OptimisticLock();

There is no Index method and we can't set options other than name for database columns. Apart from that, the rest is pretty clear and easy.


The next post in Ayende's series was about many-to-any, but I've covered it within collections and relation types, so I'm going to skip it.

Tuesday, January 31, 2012

Mapping-by-Code - Join

We have previously explored the one-to-one mapping, which lets us create 1:1 association in the database, but there is actually another way to map several tables to an object model. We aren't constrained by the database model, and we can merge several tables into a single entity. We do that using the <join> element. It can be mapped with mapping-by-code using Join method pretty easily:

Join("table_name", j =>
{
// join options
j.Table("table_name");
j.Schema("schemaName");
j.Catalog("catalogName");

j.Fetch(FetchKind.Join); // or .Select
j.Inverse(true);
j.Optional(true);

j.Key(k =>
{
k.Column("columnName");
// or
k.Column(c =>
{
c.Name("columnName");
// etc...
});

k.ForeignKey("foreignKeyName");
k.NotNullable(true);
k.OnDelete(OnDeleteAction.Cascade); // or .NoAction
k.PropertyRef(x => x.Name);
k.Unique(true);
k.Update(true);
});

j.Loader("customLoader");
j.SqlInsert("custom SQL");
j.SqlUpdate("custom SQL");
j.SqlDelete("custom SQL");
j.Subselect("custom SQL");

// joined element mappings
j.Property(x => x.MayorName);
// etc...
});

The first parameter, named mysteriously splitGroupId, is an identifier serving by default as the joined table name. The second parameter is used both for join options and mapping the joined elements.

The Key method is an equivalent of XML <key> element, that is required in join mapping. In mapping-by-code it is not required, default convention can handle it. But in case we want to customize anything about the foreign key and its database column, we have standard options available there. All the other XML mapping features are available, too - it's pretty easy to figure out as all its names matches XML attributes or elements names.

The only missing thing, as always in case of custom SQL queries, is the possibility to set up checking the value returned by the query - an equivalent for check attribute in custom queries XML elements.

Fluent NHibernate equivalent

Join mapping in Fluent NHibernate is very similiar to mapping-by-code. The first parameter of Join method is the joined table name, the second are for other options and joined element mappings.

Join("table_name", j =>
{
// join options
j.Table("table_name"); // void
j.Schema("schemaName")
.Catalog("catalogName")
.Fetch.Join() // or .Select()
.Inverse()
.Optional()
.KeyColumn("columnName");
j.SqlInsert("custom SQL").Check.RowCount();
j.SqlUpdate("custom SQL").Check.None();
j.SqlDelete("custom SQL");
j.Subselect("custom SQL");

// joined element mappings
j.Map(x => x.Name);
// etc...
});

There are few options missing - the only thing we can define about the foreign key column is its name - using KeyColumn method. The strange thing is that Table method returns void thus it's not chainable.

Monday, January 30, 2012

Mapping-by-Code - OneToOne

Moving on with relation types in NHibernate - we haven't talked about <one-to-one> yet. The name suggests that it's designed for 1:1 relationships and this is not quite correct. 1:1 relationships can be mapped simply using many-to-one with unique constraint. One-to-one is designed specifically for making that many-to-one relationship with unique constraint bidirectional.

This kind of relation is mapped using many-to-one on the side that owns the relationship (in terms of having foreign key column in the database) and one-to-one on the second side. Note that at one-to-one side there's no column at the database level - the relationship from "one" side is "virtual", maintained only by NHibernate.

In mapping-by-code we're mapping it using OneToOne method. It has two parameters. The first one is the lambda pointing to the mapped property, as always. The second one are the options.

OneToOne(x => x.User, m =>
{
m.Cascade(Cascade.Persist);
m.Constrained(true);
m.Lazy(LazyRelation.Proxy); // or .NoProxy, .NoLazy
m.PropertyReference(typeof(User).GetPropertyOrFieldMatchingName("OtherSideProperty"));
m.OptimisticLock(true);
m.Formula("arbitrary SQL expression");
m.Access(Accessor.Field);
});

Two things to note here. The first one is the lack of possibility to choose the fetch mode and foreign key name. The second one is the cumbersome construct needed to map property-ref option - the method is called PropertyReference instead of standard PropertyRef and its parameter is MethodInfo-typed instead of standard lambda expression or string at least. It looks like the feature went to production before it was finished.

Fluent NHibernate's equivalent

Fluent NHibernate's name for one-to-one is HasOne. I think this is the most often misused method in FNH as it looks like a natural sibling for HasMany and HasManyToMany and it seems to be a good choice for many-to-one mapping (which turns out to be mapped by References method). A bit messy, isn't it?

Here's how to use it:

HasOne(x => x.User)
.Cascade.SaveUpdate()
.Constrained()
.LazyLoad(Laziness.Proxy) // or .NoProxy, .False
.PropertyRef(x => x.OtherSideProperty)
.Access.Field()
.Class<CustomType>()
.Fetch.Join() // or .Select(), .Subselect()
.ForeignKey("foreignKeyName");

Apart for the name issue, it's a bit better than in mapping-by-code this time. The only option not available here is formula.

Friday, January 27, 2012

Mapping-by-Code - concurrency

It's time for less exhausting topic - concurrency mapping. There are two different aspects of concurency-related mappings.

The first one is entity-level mapping, where we choose the concurrency model (for optimistic concurrency). In XML, in <class> mapping, there are two attributes regarding the optimistic concurrency - optimistic-lock and dynamic-update. The former is not supported in mapping-by-code. The latter can be set using simple method in ClassMapping:

DynamicUpdate(true);

Another concurrency model is to use explicit versioning with separate column that keeps either timestamp or version number incremented on each update. In XML, this column is mapped using <version> element. There's corresponding method in mapping-by-code:

Version(x => x.Version, m =>
{
m.Column("columnName");
// or
m.Column(c =>
{
c.Name("columnName");
// etc...
});

m.Generated(VersionGeneration.Always); // or VersionGeneration.Never
m.UnsavedValue(0);
m.Insert(true);

m.Type(new TimestampType());
// or
m.Type<CustomType>();

m.Access(Accessor.Field);
});

The mapping is not a surprise. The first parameter is an expression pointing to mapped property, the second is for the configuration. We can specify column properties using standard Column method. We can define whether the value is generated at database side using Generated method. We can choose what value should be assigned to newly created objects using UnsavedValue method. We can also define whether the value should be considered when building insert query using Insert method. We can choose how NHibernate is accessing the value, using Access method. Finally, using the Type method, we can decide on the type used for versioning - most common are numeric and timestamp types.

Fluent NHibernate equivalents

Entity-level mappings for concurrency options in FNH are available through the two methods:

DynamicUpdate();
OptimisticLock.Dirty(); // or .All(), .None(), .Version()

And here is the mapping for version property:

Version(x => x.Name)
.Column("columnName")
.Generated.Always() // or .Never()
.UnsavedValue("0") // string?
.Access.Field()
.CustomType("timestamp")
// or
.CustomType<CustomType>();

Insert seems to be not supported. UnsavedValue is string-typed, what looks a bit strange i.e. if we want to set it to numeric value.


Two next posts in Ayende's series are about NHibernate properties mapped at global level, above entity level - <database-object>, named queries, <query> and <sql-query>. I'll skip these as they do not fit into mapping-by-code ClassMappings series. I'll maybe come back to it separately.

Tuesday, January 24, 2012

Mapping-by-Code - OneToMany and other collection-based relation types

This post is going to be a continuation for the previous one, about Set and Bag mappings. Previously I've described collection and key column mappings. This time I'll cover mapping part that defines the relation type the collection takes part in.

There are five relation types supported by collections. I'll list it with its HBM names:

  • one-to-many - when the collection elements are entities
  • many-to-many - same, but storing the relation in separate table to allow m:n relations
  • many-to-any - heterogenous association with entities of different types
  • element - when the collection elements are single-column value types
  • composite-element - when the collection elements are multiple-column value types (components)

In mapping-by-code, the relation type is defined in the third parameter of Set/Bag mapping. It is optional, with default one-to-many. There's a method for every relation type. Let's go through that methods one by one - I'll show only the lambda from third Set/Bag method parameter.

The first one is OneToMany, for one-to-many entity mapping, obviously.

r => r.OneToMany(m =>
{
m.NotFound(NotFoundMode.Exception); // or NotFoundMode.Ignore
m.Class(typeof(CustomType));
m.EntityName("entityName");
})

It has an optional parameter with configuration. NotFound defines the NHibernate behavior when the referenced entity is missing in the database. Class and EntityName allows to set up the relation for non-standard other side mappings.

Next is ManyToMany. The main difference is how the relation is stored in the database. ManyToMany relation needs an intermediate table with foreign keys to allow m:n relations. There are several options available affecting how the additional table looks like.

r => r.ManyToMany(m =>
{
m.Column("otherKeyColumnName");
// or
m.Column(c =>
{
c.Name("otherKeyColumnName");
// etc...
});

m.ForeignKey("otherKey_fk");
m.Formula("arbitrary SQL expression");
m.Lazy(LazyRelation.Proxy); // or LazyRelation.NoProxy or LazyRelation.None
m.NotFound(NotFoundMode.Exception); // or NotFoundMode.Ignore

m.Class(typeof(CustomType));
m.EntityName("entityName");
})

Configuration parameter of ManyToMany is optional - it may be skipped if we leave all options with default values and set the naming through the convention. In the options there is standard Column method that allows to define name and other DDL-level properties of the key column referencing other side entity (note that we've defined key column for our entity in bag/set mapping options) - it is useful if we don't map the other side and still be able to generate the tables properly. We can also set up laziness through Lazy method, behaviour for not found rows through NotFound or even set up the relation using arbitrary SQL expression instead of foreign key column value using Formula method.

Third one is ManyToAny. This is quite an exotic feature of NHibernate, but there are some cases where it's really useful. See Ayende's post for detailed description. Generally, this is for the case when we have a many-to-many relation with entitles of different types at the other side. NHibernate needs to be said how to distinguish the type of entity and is able to query the proper tables for different objects. Let's stick to Ayende's example:

r.ManyToAny<long>(m =>
{
m.Columns(id =>
{
id.Name("PaymentId");
id.NotNullable(true);
// etc...
}, classRef =>
{
classRef.Name("PaymentType");
classRef.NotNullable(true);
// etc...
});

m.IdType<long>(); // redundant, needs to be specified in ManyToAny parameter
m.MetaType<string>();

m.MetaValue("CreditCard", typeof(CreditCardPayment));
m.MetaValue("Wire", typeof(WirePayment));
})

The generic type in ManyToAny method defines the common type for identifiers of all entities at the other side. Inside the configuration (which is required in this case), we need to define properties for two columns this time - one to keep the other entity identifier, second to keep its discriminating value. We do it using Columns method's parameters. Later we have to specify the type of discriminator using MetaType method and its generic argument - string is good here. We can also specify the common type of identifiers using IdType method, but we've already did it in ManyToAny generic parameter (I think that this method is useless here). The last thing we need to do is to define the list of entity types that are allowed at other side of the relation and its corresponding discriminator values. In order to do this, we call MetaValue method - its first parameter is the discriminator value, second is the type.

The next collection-based relation type available is Element. This is designed for collection of simple value-typed objects, i.e. list of strings.

r => r.Element(m =>
{
m.Column("valueColumnName");
// or
m.Column(c =>
{
c.Name("valueColumnName");
// etc...
});

m.Formula("arbitrary SQL expression");
m.Length(100);
m.NotNullable(true);
m.Precision(10);
m.Scale(10);
m.Type<CustomType>(parameters);
m.Unique(true);
})

The options available are quite standard - there are DDL options for value column available within Column method and different Property-like options describing the value itself. Note that foreign key column options or table options are defined in collection options.

The last possible relation type for collection mapping is Component, known in XML as composite-element. Mapping-by-Code merged these two terms into component, because there is no real difference besides the fact that components were parts of single objects and composite elements were used in collections only.

r => r.Component(m =>
{
m.Property(x => x.Name);
// etc...
})

The mapping itself is like already described component mapping, so I'll skip it here.

Fluent NHibernate's equivalents

As I've already described in the previous post, Fluent NHibernate is not separating the collection mapping from the relation mapping, mixing it together in one method chain. Many-to-any relation is not supported by FNH, and the remaining four types of relations are mapped differently.

Let's go through the mappings - I'll skip the options regarding collection mapping and reflect only these options, that are part of relation mappings in mapping-by-code to keep the comparison consistent.

The first one is HasMany for one-to-many relation:

HasMany(x => x.Users)
.NotFound.Ignore() // or .Exception()
.EntityName("entityName");

HasManyToMany is for many-to-many:

HasManyToMany(x => x.Users)
.ChildKeyColumn("otherKeyColumnName")
.ForeignKeyConstraintNames("parentForeignKeyName", "childForeignKeyName")
.NotFound.Ignore() // or .Exception()
.EntityName("entityName");

Formula mapping is missing. Foreign key name configuration is joined for both sides. There are few more options regarding "child" (other entity) key column, all with names starting with Child.

Many-to-any relation is not supported in Fluent NHibernate.

The next one is element relation, merged into HasMany method, available in the chain through Element method:

HasMany(x => x.Users)
.Element("valueColumnName", m =>
{
m.Formula("arbitrary SQL expression")
.Length(100)
.Type<CustomType>();
})

Other element relation options are not supported.

And finally, there is composite element (component) mapping, named Component here, too. It is also merged into HasMany chain.

HasMany(x => x.Users)
.Component(m =>
{
m.References(x => x.Name);
// etc...
})

Saturday, January 21, 2012

Mapping-by-Code - Set and Bag

It's time for a huge topic - collections. The original Ayende's post was about <set> in the context of one-to-many relationship. I'm going to change it a bit and start with showing how to map sets and bags using mapping-by-code vs. Fluent NHibernate, ignoring the relation context (i.e. one-to-many or many-to-many) - it is clearly separated both in XML mapping and in mapping-by-code. I'll describe different relation types mappings handled by sets and bags in the separate post.

Contrary to Fluent NHibernate and likewise XML mapping, the collection type is a starting point for the mapping. The options are exactly the same in <set> and <bag>, they differ only with the method name - Set vs. Bag. I'll show Set here, for Bag just change the method called in the first line.

Set(x => x.Users, c =>
{
c.Fetch(CollectionFetchMode.Join); // or CollectionFetchMode.Select, CollectionFetchMode.Subselect
c.BatchSize(100);
c.Lazy(CollectionLazy.Lazy); // or CollectionLazy.NoLazy, CollectionLazy.Extra

c.Table("tableName");
c.Schema("schemaName");
c.Catalog("catalogName");

c.Cascade(Cascade.All);
c.Inverse(true);

c.Where("SQL command");
c.Filter("filterName", f => f.Condition("condition"));
c.OrderBy(x => x.Name); // or SQL expression

c.Access(Accessor.Field);
c.Sort<CustomComparer>();
c.Type<CustomType>();
c.Persister<CustomPersister>();
c.OptimisticLock(true);
c.Mutable(true);

c.Key(k =>
{
k.Column("columnName");
// or...
k.Column(x =>
{
x.Name("columnName");
// etc.
});

k.ForeignKey("collection_fk");
k.NotNullable(true);
k.OnDelete(OnDeleteAction.NoAction); // or OnDeleteAction.Cascade
k.PropertyRef(x => x.Name);
k.Unique(true);
k.Update(true);
});

c.Cache(x =>
{
x.Include(CacheInclude.All); // or CacheInclude.NonLazy
x.Usage(CacheUsage.ReadOnly); // or CacheUsage.NonstrictReadWrite,
// CacheUsage.ReadWrite, CacheUsage.Transactional
x.Region("regionName");
});

c.SqlDelete("SQL command");
c.SqlDeleteAll("SQL command");
c.SqlInsert("SQL command");
c.SqlUpdate("SQL command");
c.Subselect("SQL command");
c.Loader("loaderRef");
}, r =>
{
// one of the relation mappings (to be described separately)
r.Element(e => { });
r.Component(c => { });
r.OneToMany(o => { });
r.ManyToMany(m => { });
r.ManyToAny<IAnyType>(m => { });
});

Whoa! The first parameter, not surprisingly, is the lambda expression for the collection property we're mapping. Second one allows to configure the set/bag using a bunch of options. Third one, optional, defines the type of relation the collection takes part in - one-to-many by default (I'll write about relation types separately).

Let's see what options set and bag have to offer and how it differs from XML mappings.

Fetch, BatchSize and Lazy define how and when the collection is loaded from the database. Table, Schema and Catalog say where to look for the collection data in the database. Inverse is useful for bidirectional relationships and defines which side is responsible for writing.

Cascade tells how operations on the entity affects the collection elements. Note that in mapping-by-code it is redefined a bit. Here are the possible values and its corresponding XML values (note that All still doesn't mean literally all values; DeleteOrphans still needs to be specified aside).

[Flags]
public enum Cascade
{
None = 0, // none
Persist = 2, // save-update, persist
Refresh = 4, // refresh
Merge = 8, // merge
Remove = 16, // delete
Detach = 32, // evict
ReAttach = 64, // lock
DeleteOrphans = 128, // delete-orphans
All = 256, // all
}

Combining the values can be done using logical | operator or using syntax provided through extension methods:

Cascade.All.Include(Cascade.DeleteOrphans);

Coming back to bag/set options. Where, Filter and OrderBy affect what data are loaded from the database. Where and OrderBy allows to specify any SQL expression for narrowing and sorting the collection at database level. Furthermore, OrderBy has an overload that makes it possible to specify the ordering by an expression, too. Filter is even more powerful - see another Ayende's post for an explanation.

All the options above, up to Key call in my example, have corresponding XML attributes in <bag> or <set> XML element. Key and all further options are defined in XML as separate elements inside <bag> or <set>.

Key is to define key column in the table that holds collection elements - there are some DDL parameters and behaviors configurable. Key method is a direct equivalent of mandatory <key> element in XML.

Cache controls the second level cache behaviors for the collection. It's an equivalent of <cache> element in XML.

All the SqlXYZ methods are to set up custom ways of reading and writing collection to the database and all of it have its corresponding XML elements, too - useful if we have to use stored procedures for data access. In XML mappings, there's also an ability to tell NHibernate to check what was returned from the procedure, but it seems not supported by mapping-by-code.

The only attribute of Set and Bag that is not configurable in mapping-by-code is generic. It is to determine whether the collection type used is generic. But by default, NHibernate checks this on its own by reflection and I can't see why anyone would need to override this behavior.

Fluent NHibernate's equivalent

Fluent NHibernate redesigned the approach established by XML mappings and made a relation type an entry point (and only required part) of the mapping. Moreover, only relations with entities at the other side are considered "first-class citizens" by FNH. So there are only two entry methods: HasMany and HasManyToMany. Element and component (composite element) mappings are hidden inside HasMany as its options. Many-to-any seems to be not supported.

As I'm not describing relationship types in this post, I'll pick many-to-one as an example just to have an entry point and I'll skip the options connected with relationship itself, focusing on collection and key column options. This way it'll cover about the same options as in mapping-by-code example.

HasMany(x => x.Users)
.AsSet<CustomComparer>() // or .AsSet(), .AsBag()
.Fetch.Join()
.BatchSize(100)
.LazyLoad() // or .ExtraLazyLoad()
.Table("tableName")
.Schema("schemaName")
.Cascade.AllDeleteOrphan() // or .None(), .SaveUpdate(), .All(), DeleteOrphan()
.Inverse()
.Where("SQL command") // or an boolean lambda expression
.ApplyFilter("filterName", "condition")
.OrderBy("SQL expression")
.Access.Field()
.CollectionType<CustomType>()
.Persister<CustomPersister>()
.OptimisticLock.Version() // buggy
.ReadOnly()
.Generic()
.KeyColumn("columnName")
.ForeignKeyConstraintName("collection_fk")
.Not.KeyNullable()
.ForeignKeyCascadeOnDelete()
.PropertyRef("propertyRef")
.KeyUpdate()
.Subselect("SQL command")
.Cache.IncludeAll() // or .IncludeNonLazy, .CustomInclude("customInclude")
.ReadOnly() // or .NonStrictReadWrite(), .ReadWrite(), .Transactional(), .CustomUsage("customUsage")
.Region("regionName");

List of possible options is quite long, too. Let's go through and note the major differences.

AsSet method needs to be called to change the default collection type (bag) to set. I've already mentioned that I don't like the fact that such a fundamental thing like collection type is just an ordinary, optional switch in FNH. Moreover, the overloads with comparer (being equivalent of Sort from mapping-by-code) make AsSet method look like the comparer is the only sense of its existence. And that's obviously not the case.

Several options have names changed in FNH:

  • Filter and its Condition are merged into ApplyFilter,
  • Type is CollectionType this time (instead of FNH's standard CustomType),
  • Column is KeyColumn,
  • ForeignKey is ForeignKeyConstraintName,
  • NotNullable is Not.KeyNullable,
  • OnDelete(OnDeleteAction.Cascade) is mapped by ForeignKeyCascadeOnDelete,
  • Update is KeyUpdate,
  • and finally, quite confusing, Mutable is ReadOnly in FNH. It wouldn't be so surprising if FNH didn't use ReadOnly as a shortcut for Not.Update and Not.Insert in other mappings. And Mutable is something different.

There are several options not supported in FNH, i.e. Catalog, Unique, Loader and custom SQL queries (the latter is surprising, as custom SQL queries are available in component mapping, where it shouldn't). In Cascade, there are only a few options - the less used ones like refresh are not supported.

OptimisticLock is buggy. It allows to define concurrency strategies that are valid at entity level only. For collections, OptimisticLock is just a boolean flag. Running the example above (with invalid .Version() call) results in XML validation error.

There's also a problem with an interface being too fluent, again. When defining cache options, we can in fact define all its values together, what makes no sense.

m.Cache.IncludeAll().IncludeNonLazy().CustomInclude("customInclude")
.ReadOnly().NonStrictReadWrite().ReadWrite().Transactional().CustomUsage("customUsage");

Moreover, when we step into cache configuration, we have no way to go back to collection-level options - so Cache configuration needs to be at the end.

An interesting option available only in Fluent NHibernate is specifying Where condition using an expression. It seems to work only if property names are equal to column names, but anyway, it's much better than plain SQL expression in a magic string (for more complicated cases, this fallback is available, too).

What is surprising, PropertyRef is opposite - it needs to be specified by string in FNH, when mapping-by-code supports strongly-typed expression there.

Wednesday, January 18, 2012

Mapping-by-Code - dynamic component

Dynamic component is a feature that allows to map non-generic key-value collection as a part of our entity, like ordinary properties.

Dynamic component was the hardest feature to map using mapping-by-code up to date. I was cursing at the lack of documentation or examples and struggling with NHibernate's source code for few hours and I was ready to show a white flag this time or assume that this feature is broken in mapping-by-code. Finally I've figured it out - it does work and it's quite neat, actually.

There's no separate method for defining dynamic components in mapping-by-code - overloads of the Component method are used. Here is the overload to be used with accessible IDictionary-typed property:

public void Component<TComponent>(
Expression<Func<TEntity, IDictionary>> property,
TComponent dynamicComponentTemplate,
Action<IDynamicComponentMapper<TComponent>> mapping)
where TComponent : class
{
this.RegisterDynamicComponentMapping<TComponent>(property, mapping);
}

I've pasted the whole code of this method to share my initial confusion. Second parameter, dynamicComponentTemplate, is not used at all and it didn't make a hint what TComponent should be. But it turned out to be very useful. Instead of specifying name and type for each key-value pair, we use this parameter to pass an anonymous class instance being a template. Each key from IDictionary should be defined as a property in the template and any value that allows to determine the proper type should be passed.

The third parameter are the mapping options. Thanks to the template and its anonymous but concrete type, we are now defining the properties mapping as if these are ordinary entity properties. Quite neat, isn't it?

My mapped entity has an IDictionary-typed property. I'm going to persist values for "Founded" and "Municipality" string-typed keys.

entity.Properties["Founded"] = 1497;
entity.Properties["Municipality"] = session.Load<Municipality>(1);

Here's how to map it:

Component(x => x.Properties, new
{
Founded = 0,
Municipality = default(Municipality)
}, dc =>
{
// dynamic component members mappings
dc.Property(x => x.Founded);
dc.ManyToOne(x => x.Municipality);
// etc.

// dynamic component options
dc.Access(Accessor.Property);
dc.Insert(true);
dc.Update(true);
dc.OptimisticLock(true);
dc.Unique(true);
});

My IDictionary-typed property called Properties is specified in the first parameter. "Founded" and "Municipality" keys are defined as properties in the template class (second parameter). Corresponding values from the dictionary will be persisted correctly, thanks to the members mappings defined in the third parameter. Properties dictionary can contain anything - collections, other components etc. - all the entity-level mappings are available here, too.

There are also a few options that define behaviors for the component as a whole, like Access or OptimisticLock. These can be redefined at members mappings options, as usual.

Fluent NHibernate's equivalent

Mapping dynamic components in FNH is easier to figure out, but not so clever - key strings and types needs to be defined explicitly.

DynamicComponent(x => x.Properties, dc =>
{
// dynamic component members mappings
dc.Map<int>("Founded");
dc.References<Municipality>(x => x["Municipality"]);

// dynamic component options
dc.Access.Property()
.Insert()
.Update()
.OptimisticLock()
.Unique()
.ParentReference(x => x["Parent"])
.ReadOnly();

dc.SqlDelete("SQL command");
dc.SqlDeleteAll("SQL command");
dc.SqlInsert("SQL command");
dc.SqlUpdate("SQL command");
});

ReadOnly is just a FNH's shortcut for setting both .Not.Insert() and .Not.Update().

This FNH mapping suffers for the same bug as in case of FNH's Component mapping. It is not possible to map ParentReference or SQL queries for dynamic component and FNH should not expose these options as they have no way to work correctly. In fact, SQL queries are ignored and defining ParentReference causes XML validation error.

Monday, January 16, 2012

Mapping-by-Code - inheritance

Next article in Ayende's NHibernate mapping series is about inheritance mappings. As we know, there are few different approaches to inheritance in database. Let's see how we can map it using NHibernate's 3.2 mapping-by-code.

Let's use the same model as Ayende did:

Single table

And let's begin with single table approach (table per hierarchy):

public class PartyMap : ClassMapping<Party>
{
public PartyMap()
{
Id(x => x.Id, i => i.Generator(Generators.HighLow));

Discriminator(x =>
{
x.Force(true);
x.Formula("arbitrary SQL expression");
x.Insert(true);
x.Length(12);
x.NotNullable(true);
x.Type(NHibernateUtil.String);

x.Column("discriminator");
// or...
x.Column(c =>
{
c.Name("discriminator");
// c.Length(21);
// c.NotNullable(false);
// etc.
});
});
}

public class CompanyMap : SubclassMapping<Company>
{
public CompanyMap()
{
DiscriminatorValue("Company");
Property(x => x.CompanyName);
}
}

public class PersonMap : SubclassMapping<Person>
{
public PersonMap()
{
DiscriminatorValue("Person");
Property(x => x.FirstName);
}
}
}

Single table inheritance mapping consists of two parts - discriminator mapping and subclasses mappings.

Discriminator column is mapped with Discriminator method. Mapping options offered by this method looks a bit messy. Length and NotNullable methods are available both in the Column method options (as in other mappings) and in the discriminator options directly. It looks like they are equivalent, what's called last "wins".

Mapping of subclasses is done through separate mapping classes that inherit from SubclassMapping<T>.

An important thing to remember when mapping inheritance using mapping-by-code is that when registering our mappings we should not look for ClassMapping<T> inheritors only - SubclassMapping<T> (and JoinedSubclassMapping<T> and UnionSubclassMapping<T>, mentioned later) do not inherit from ClassMapping<T>. The solution I'm using is to look for all implementations of IPropertyContainerMapper<T>.

Fluent NHibernate's equivalent for single table

Single table inheritance mapping is almost identical in Fluent NHibernate to mapping-by-code:

public class PartyMap : ClassMap<Party>
{
public PartyMap()
{
Id(x => x.Id).GeneratedBy.HiLo(maxLo: "100");

DiscriminateSubClassesOnColumn("discriminator")
.AlwaysSelectWithValue()
.Formula("arbitrary SQL expression")
.ReadOnly()
.Length(12)
.Not.Nullable()
.CustomType<string>();
}

public class CompanyMap : SubclassMap<Company>
{
public CompanyMap()
{
DiscriminatorValue("Company");
Map(x => x.CompanyName);
}
}

public class PersonMap : SubclassMap<Person>
{
public PersonMap()
{
DiscriminatorValue("Person");
Map(x => x.FirstName);
}
}
}

The way of defining subclasses is identical. The discriminator mapping differs in few names: Force is AlwaysSelectWithValue in FNH, Type is CustomType and Insert(false) can be mapped using ReadOnly. Moreover, the DiscriminateSubClassesOnColumn method, that is an entry point for discriminator mapping, requires specifying discriminator column name explicity - no default provided.

There are some more standard column-related methods available, analogously to mapping-by-code Column method options.

Table per class

The second strategy for mapping inheritance is table per class with joined subclasses. In this option subclasses are stored in separate tables that have foreign key to base class table and are joined with the table for base class, if needed. In this case, in mapping-by-code, we have to map subclasses by inheriting from JoinedSubclassMapping<T>. Here is the example of joined subclass mapping with all available options:

public class CompanyMap : JoinedSubclassMapping<Company>
{
public CompanyMap()
{
Key(k =>
{
k.Column("PartyId");
// or...
k.Column(c =>
{
c.Name("PartyId");
// etc.
});

k.ForeignKey("party_fk");
k.NotNullable(true);
k.OnDelete(OnDeleteAction.Cascade); // or OnDeleteAction.NoAction
k.PropertyRef(x => x.CompanyName);
k.Unique(true);
k.Update(true);
});

Property(x => x.CompanyName);
}
}

Fluent NHibernate's equivalent for table per class

In Fluent, subclasses are mapped by inheriting from the same SubclassMap<T> as in single table strategy. Only the method used differs - instead of DiscriminatorValue, we're using KeyColumn method with column name in the parameter (required, no default value). Looks like there's no way to configure other key column's options here.

public class CompanyMap : SubclassMap<Company>
{
public CompanyMap()
{
KeyColumn("PartyId");
Map(x => x.CompanyName);
}
}

Table per subclass

The third option is to use table per subclass with unioned subclasses. This time there is no separate table for base class, common columns are specified in each table for subclass separately and subclass tables share the same key generator. Mapping union subclasses with mapping-by-code is fairly simple - we just need to map the class by inheriting from UnionSubclassMapping<T> - no additional requirements or options.

public class CompanyMap : UnionSubclassMapping<Company>
{
public CompanyMap()
{
Property(x => x.CompanyName);
}
}

Fluent NHibernate's equivalent for table per subclass

Again, in Fluent, subclass maps inherit from the same SubclassMap<T>. To differentiate this strategy from the single table strategy, we have to include a call to UseUnionSubclassForInheritanceMapping method in the parent class mapping.

public class PartyMap : ClassMap<Party>
{
public PartyMap()
{
Id(x => x.Id).GeneratedBy.HiLo(maxLo: "100");
UseUnionSubclassForInheritanceMapping();
}

public class CompanyMap : SubclassMap<Company>
{
public CompanyMap()
{
Map(x => x.CompanyName);
}
}

public class PersonMap : SubclassMap<Person>
{
public PersonMap()
{
Map(x => x.FirstName);
}
}
}

Friday, January 13, 2012

Mapping-by-Code - ManyToOne

Next up for inspection for mapping-by-code is the <many-to-one> element. It's mapping-by-code equivalent is ManyToOne. Here are its possible options:

ManyToOne(x => x.PropertyName, m =>
{
m.Column("column_name");
// or...
m.Column(c =>
{
c.Name("column_name");
// other standard column options
});

m.Class(typeof(ClassName));
m.Cascade(Cascade.All | Cascade.None | Cascade.Persist | Cascade.Remove);
m.Fetch(FetchKind.Join); // or FetchKind.Select
m.Update(true);
m.Insert(true);
m.Access(Accessor.Field);
m.Unique(true);
m.OptimisticLock(true);

m.Lazy(LazyRelation.Proxy);

//m.PropertyRef ???
//m.NotFound ???

m.ForeignKey("column_fk");
m.Formula("arbitrary SQL expression");
m.Index("column_idx");
m.NotNullable(true);
m.UniqueKey("column_uniq");
});

The first parameter (as almost always) is an lambda expression specifying mapped property in our entity. The second (as almost always) are the mapping options.

Column method (as almost always, again) is to specify database column that keeps the relation value. By default, its name is equal to property name, without any "_id" postfix or something. We can change its name only using the overload with string or we can customize all the options using the second overload. Its possibilities are shown in the post about property mapping - it generally works the same way, so I'll skip it here.

Cascade is used pretty often. Note that mapping-by-code redefined it a bit: save-update option is called Persist and delete is Remove here. This is configured using an flags-type enumerable, so it's easy to combine values. There's also an alternative syntax provided using extension methods:

    m.Cascade(Cascade.Persist.Include(Cascade.Remove));

By now, there's no way to map two features useful for legacy inconsistent databases - property-ref and not-found. Maybe Fabio decided that legacy databases wouldn't be mapped with new mappings?

Fluent NHibernate's equivalent

ManyToOne's equivalent in FNH is References:

References(x => x.PropertyName, "column_name")
.Class<ClassName>()
.Cascade.SaveUpdate()
.Fetch.Join()
.Update()
.Insert()
.ReadOnly()
.Access.Field()
.Unique()
.OptimisticLock()
.LazyLoad(Laziness.Proxy)
.PropertyRef(x => x.PropertyRef)
.NotFound.Ignore()
.ForeignKey("column_fk")
.Formula("arbitrary SQL expression")
.Index("column_idx")
.Not.Nullable()
.UniqueKey("column_uniq");

ReadOnly is just a FNH's shortcut for setting both .Not.Insert() and .Not.Update().

Wednesday, January 11, 2012

Mapping-by-Code - Component (and odd cases of Fluent NHibernate's fluency)

Let's move on with mapping-by-code vs. XML vs. Fluent NHibernate. The second post in Ayende's series was about <component> mapping. It's equivalent in mapping-by-code is Component, of course. There are total 6 overloads for Component method - 3 parametrized with lambda expression and 3 with strings for cases where the property is not publicly visible. In each three, there is an overload designed for dynamic components, which are separate topic. So the overloads that interest us have signatures like this:

public void Component<TComponent>(
Expression<Func<TEntity, TComponent>> property,
Action<IComponentMapper<TComponent>> mapping)
where TComponent : class

The first parameter is an lambda expression specifying the property of type TComponent. The second is the component mapping itself - it can contain component's properties mapping (and other class mapping parts except Id) and some options defining component's behavior.

Component(x => x.Address, c =>
{
// mappings for component's parts
c.Property(x => x.City);
c.Property(x => x.ZipCode);
// etc...

// mappings for component's options
c.Parent(x => x.Owner, p => p.Access(Accessor.ReadOnly));
c.Access(Accessor.Property); // or Accessor.Field or Accessor.ReadOnly
c.Class<TownHallAddress>();

c.Insert(true);
c.Update(true);
c.OptimisticLock(true);
c.Lazy(true);
});

Mapping for component's parts can of course contain its own options - i.e. see previous post for Property options.

Parent is a way to create bidirectional relationship between component and its owning entity - it allows mapping back to entity. The only thing that can be customized about this relationship is how should NHibernate access the Parent property in component class - using Access method. This needs to be distinguished from component's Access method, that affects how NHibernate access the opposite - component property in entity. Insert, Update, OptimisticLock and Lazy are about the latter property, too.

One thing is probably missing - both XML and Fluent mapping allows to add Unique constraint on the component, I can't see how to do it with mapping-by-code.

Fluent NHibernate's equivalent

One of the ways to map component in FNH is:

Component(x => x.Address, c =>
{
// mappings for component's parts
c.Map(x => x.City);
c.Map(x => x.ZipCode);
// etc...

// mappings for component's options
c.ParentReference(x => x.Owner)
.Access.ReadOnly()
.Insert()
.Update()
.OptimisticLock()
.LazyLoad()
.ReadOnly()
.Unique();

c.SqlUpdate("update query")
c.SqlInsert("insert query")
c.SqlDelete("delete query")
c.SqlDeleteAll("delete all query")
});

ReadOnly is just a FNH's shortcut for setting both .Not.Insert() and .Not.Update().

Note that Fluent NHibernate allows to specify raw SQL queries for updates, inserts and deletes - mapping-by-code doesn't. But this is not mapping-by-code's limitation, it's rather a FNH bug. Mapping raw queries doesn't make a sense for components, that are by definition owned and managed by its owning entity and NHibernate's XML schema doesn't even allow these attributes in component mapping.

Moreover, FNH's fluency introduces a lot of confusion in cases like this:

c.ParentReference(x => x.Owner).Access.ReadOnly();

It may look like defining an access strategy for parent reference, but no - it is defining an access strategy for the component itself and there's no way to set the former in Fluent NHibernate (at least I can't see any).

Note also that there are three alternative ways to attach component's options and all of it seems to work the same:

Component(x => x.Address, c =>
{
c.LazyLoad().ParentReference(x => x.Owner);
c.ParentReference(x => x.Owner);
})
.ParentReference(x => x.Owner);

And - continuing the exploration of Fluent's API odd cases - setting access strategy and disabling the component from update and insert queries looks like that:

c.Access.ReadOnly().ReadOnly();

Well, now I clearly see the limitations of fluent interfaces. In Fluent NHibernate it can sometimes be more confusing than helpful. Mapping-by-code seems to have much more elegant solution here.

Monday, January 9, 2012

Mapping-by-Code - Property

I am spending quite a lot of time recently with NHibernate 3.2 mapping-by-code feature and as I've already mentioned, my most serious obstacle with this evaluation is that there is virtually no resources on the net. If these answers are everything the Web has to offer, there's a lot of space for improvement.

I am planning to prepare a series of posts covering the most important NHibernate's mapping features implemented using mapping-by-code. I'll probably follow Ayende's great series about XML mappings, at least in terms of ordering. I'm not going to describe the features itself, I'll rather focus on mapping interface. For features description - refer to Ayende's posts.

So let's start with <property>. Its equivalent in mapping-by-code is... Property - isn't it surprising? Well, in Fluent NHibernate it is called Map. There's no rocket science here and everything is pretty simple.

Property(x => x.Property, m =>
{
m.Column("columnName");
// or
m.Column(c =>
{
c.Name("columnName");
c.Default("defaultValue");

c.SqlType("varchar(max)");
c.Length(SqlClientDriver.MaxSizeForLengthLimitedString + 1);

c.NotNullable(true);
c.Check("len(columnName) > 1");
c.Precision(2);
c.Scale(2);
c.Index("column_idx");
c.Unique(true);
c.UniqueKey("column_uniq");
});

m.Type<string>(); // or IUserType
m.Update(true);
m.Insert(true);
m.Formula("arbitrary SQL expression");

m.Access(Accessor.Field); // or Accessor.Property or Accessor.NoSetter
// or
m.Access(typeof(CustomAccessor));

m.OptimisticLock(false);
m.Generated(PropertyGeneration.Insert); // or PropertyGeneration.Always or PropertyGeneration.Never

m.Lazy(true);
});

Mapped property goes as lambda expression (or string property name, if it is hidden) in first parameter and this is the only obligatory element - everything else has its defaults and can be skipped (and most often, it should). All the other attributes from the XML have its corresponding method in configuration object in second parameter.

One thing to note is that column can be configured using Column method either with simple string (when customising only name) or with column configuration, that allows to set different DDL-level column properties. Not every feature is implemented in every provider and not every feature makes sense for every column type obviously - i.e. Precision and Scale are for numerics only.

Side note: In the example above I'm specifying SqlType explicitly to varchar(max), but this line

Property(x => x.Name, m => m.Length(SqlClientDriver.MaxSizeForLengthLimitedString + 1));

will also produce varchar(max) in SQL Server, and that solution seems to be nicer.

Fluent NHibernate's equivalent

Map(x => x.Property, "columnName")
.Default("defaultValue")
.CustomSqlType("varchar(max)")
.Length(SqlClientDriver.MaxSizeForLengthLimitedString + 1)
.Not.Nullable()
.Check("len(columnName) > 1")
.Precision(2)
.Scale(2)
.Index("column_idx")
.Unique()
.UniqueKey("column_uniq")
.CustomType<string>()
.Update()
.Insert()
.Formula("arbitrary SQL expression")
.Access.Field()
// or .Access.Using<CustomAccessor>()
.OptimisticLock()
.Generated.Insert()
.LazyLoad()
.ReadOnly();

The only difference apart from different naming for some properties and Property vs. Map name itself is the ReadOnly method available in FNH. It is just a shortcut for setting both .Not.Insert() and .Not.Update().

Sunday, November 27, 2011

Many-to-many mapping: collection types

In the previous post we've seen how to instruct NHibernate to generate proper number of INSERT statements to intermediate many-to-many table using Inverse attribute. Time for something bit more complicated.

In the previous example we've created fresh instances of Users and Group and used it in the same session, so NHibernate knew the collections were initially empty. Let's see what happens when we want to work with the collections that are fetched from the database with lazy loading, so that NHibernate doesn't know the collections.

In the example below we're just trying to remove second User from the Group - a task that could be accomplished with single DELETE statement.

using (var sess = factory.OpenSession())
using (var tx = sess.BeginTransaction())
{
var group = sess.Get<Group>(1);
var user2 = sess.Load<User>(2);

group.Users.Remove(user2);
tx.Commit();
}

And here are the queries run in this session:

Well, we just wanted to delete single row from GroupsToUsers, but NHibernate decided to load the collection of users assigned to our Group with ID=1, purge the whole collection, remove the entry in memory and re-add rows that left one by one (which may be thousands of rows!). Seems a bit redundant, doesn't it?

To understand what happened here, first we need to know the difference between the collection types supported by NHibernate and which are used by default by Fluent NHibernate if we didn't specify it explicitly.

There are two collection types that are important for many-to-many mappings - bags and sets:

  • bag is the simplest container - it just holds any items without uniqueness checking
  • set is unique - it means that it can't have two items with exactly the same values

In my object model, I've defined the collections properties using ICollection<T> interface. It seems to be the good choice as it's the base interface for all collections. But ICollection doesn't give any hint to Fluent NHibernate which type of collection to use and Fluent NHibernate chooses the simplest one, which is bag.

I think Fluent NHibernate is wrong with hiding the decision which collection type to use somewhere in conventions. This changes a lot in how NHibernate behaves and the choice should be explicit at mapping level, so that we'll need to think about it instead of letting Fluent to choose something what could be highly inappropriate.

OK, so now we know that our Users collection in Group is implicitly defined as bag. Why it recreates the whole collection just to remove one row? This is just how bag works. Bag doesn't have a primary key and NHibernate can't construct SQL query that addresses the single row to delete - WHERE User_id = 2 AND Group_id = 1 is ambiguous when the row is duplicated (and it can be, as we saw in the previous post). NHibernate's strategy to solve that problem, which we saw above, is obviously the simplest one, but at least it makes us think and look for another solution.

In case of many-to-many, in almost all cases, we in fact need set semantics. Duplicate rows in intermediate table have no meaning and should be forbidden at database level using primary key constraint.

So let's map our Users collection in Group classmap as set:

// in UserMap
HasManyToMany(x => x.Groups).Inverse();

// in GroupMap
HasManyToMany(x => x.Users).AsSet();

Note that we can leave the collection at User side with default bag mapping because it is marked as Inverse, so there is no database write triggered from there and read efficiency is the same with bag and set (it's just a SELECT to fetch all data by foreign key).

Let's look at the queries from our session this time:

Much better. There is no DELETE statement for whole collection and there is no re-inserting. There's just one DELETE that will affect one row only (this is guaranteed by set semantics).

Why do we need to load the collection anyway (statement #2)? I'll explain it in the next post, together with summary and conclusions for many-to-many mappings.