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.

2 comments:

  1. It is bidirectional in database model in http://ayende.com/blog/3961/nhibernate-mapping-join. Is it still the same via mapping by xml and mapping-by-code?

    ReplyDelete
    Replies
    1. What do you mean by "bidirectional in database model"? In Ayende's example, only Addresses table has a reference to People, can't have an Address without a row in People. And yes, as far as my experiments have shown, it's still equivalent to xml mapping.

      Delete