Note: this is a cross post from my own blog.
This post is an exercise, similar to this and this previous posts about using NHibernate mapping by code new features present form version 3.2. The source inspiring it is an old post form Ayende, showing a non trivial requirement to map.
Here the DB model:
And the wanted object model:
So there is a lot of comments about DB refactoring needing, or on needing to have the linking entity as a visible entity in the model, but:
Ayende solves the trouble by the <join/> mapping having an entity spawning two tables, so Address will be represented by joining the Table Address and PeopleAddress.
This can be done very easily in Mapping by code too, lets see how:
ModelMapper mapper = new ModelMapper(); mapper.Class<Person>(m => { m.Id(k => k.Id,g=>g.Generator(Generators.Native)); m.Table("People"); m.Property(k => k.Name); m.Bag(k => k.Addresses, t => { t.Table("PeopleAddresses"); t.Key(c=>c.Column("PersonId")); t.Inverse(true); } ,rel=>rel.ManyToMany(many=>many.Column("AddressId")) ); } ); mapper.Class<Address>(m => { m.Id(k => k.Id, g => g.Generator(Generators.Native)); m.Table("Addresses"); m.Property(p => p.City); m.Join("PeopleAddresses", z =>
{
z.Property(p => p.IsDefault);
z.Property(p => p.ValidFrom);
z.Property(p => p.ValidTo);
z.Key(k => k.Column("PersonId"));
}); } );
That yield the following mapping:
<?xml version="1.0" encoding="utf-16"?> <hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="TestMappingByCode" assembly="TestMappingByCode" xmlns="urn:nhibernate-mapping-2.2"> <class name="Person" table="People"> <id name="Id" type="Int32"> <generator class="native" /> </id> <property name="Name" /> <bag name="Addresses" table="PeopleAddresses" inverse="true"> <key column="PersonId" /> <many-to-many class="Address" column="AddressId" /> </bag> </class> <class name="Address" table="Addresses"> <id name="Id" type="Int32"> <generator class="native" /> </id> <property name="City" /> <join table="PeopleAddresses"> <key column="PersonId" /> <property name="IsDefault" /> <property name="ValidFrom" /> <property name="ValidTo" /> </join> </class> </hibernate-mapping>
Exactly the ones that Ayende proposed. As you can see is pretty straightforward map even a not so common situation.