Nov 2, 2010

ConfOrm nice column naming conventions

I have decided to write all further posts in English. The reason for that is simple – when I try to find something related to programming topics I always use English. I think most people do the same.

The next step of learning ConfOrm for me was creation of sharp-architecture like conventions for table and column mappings.  I even wrote some pattern appliers, but when ManyToMany turn has came I had to google a bit. And the result was that Conform.Shop already implemented everything that I wanted so this post will be about usage of this library and the next one about implementation of your own appliers.

To create your own naming conventions we need to understand overall process. Basically mapping in ConfOrm  consists of two major steps:

  1. Getting the domain entities. This is done with the help of ObjectRelationalMapper class. This class is responsible for creating all the entities and associations between them. So is you want to change association type, or remove some property from the mappings this a place where you should do it.
  2. Creating mappings. Mapper class is responsible here. If you want to provide tables, columns and other conventions this is the right place.

Lets begin with domain model:

domain model 

Simple but with some associations.

Probably the easiest way to understand how NHibernate is configured is to look at XML (ConfOrm doesn't generate XML, but you can get it with this approach). So lets check User entity map:

<class name="User">
  <id name="Id" type="Int32">
    <generator class="native" />
  </id>
  <property name="FirstName" />
  <property name="LastName" />
  <property name="VeryLongProperty" />
  <set name="Orders" inverse="true" cascade="all,delete-orphan">
    <key column="User" on-delete="cascade" />
    <one-to-many class="Order" />
  </set>
</class>

The first thing that I want to change is the table name. I want it to be plural. To do this all that is required to do the following:

var englishInflector = new EnglishInflector();
mapper.PatternsAppliers.Merge(
                       new ClassPluralizedTableApplier(englishInflector));

There are also SpanishInflector and ItalianInflector if somebody wants them. After adding this one we get directive table=Users and so on for all other entities.

Next thing that I don’t like is names for column in the <key property. To change it I need to do the following:

mapper.PatternsAppliers.Merge(
new OneToManyKeyColumnApplier(relationalMapper));

Now the mapping for the set is:

<set name="Orders" inverse="true" cascade="all,delete-orphan">
  <key column="UserId" on-delete="cascade" /> 
  <one-to-many class="Order" /> 
</set>

That is probably all that I wanted to change in User mapping. Now Lets look at the Product map:

<class name="Product" table="Products">
  <id name="Id" type="Int32">
    <generator class="native" />
  </id>
  <property name="Price" />
  <property name="Name" />
  <property name="Description" />
  <set name="Categories" table="CategoryProduct" inverse="true">
    <key column="product_key" />
    <many-to-many class="Category" column="category_key" />
  </set>
</class>

There is definitely a better way of naming columns in the joining table. To change them we need to add next appliers:

mapper.PatternsAppliers.Merge(
                      new ManyToManyColumnApplier(relationalMapper));
mapper.PatternsAppliers.Merge(
                      new ManyToManyKeyIdColumnApplier(relationalMapper));

Those will give:

<set name="Categories" table="CategoryProduct" inverse="true">
  <key column="ProductId" />
  <many-to-many class="Category" column="CategoryId" />
</set>

That is what I really wanted. So all the mappings for the domain:

var relationalMapper = new ObjectRelationalMapper();
relationalMapper.TablePerConcreteClass(domainEntities);
relationalMapper.Patterns.PoidStrategies.Add(new NativePoidPattern());
relationalMapper.Cascade<Category, Product>(Cascade.Persist);
relationalMapper.ManyToMany<Category, Product>();
relationalMapper.Cascade<Order, Product>(Cascade.Persist);

var mapper = new Mapper(relationalMapper);
var englishInflector = new EnglishInflector();
mapper.PatternsAppliers.Merge(new ClassPluralizedTableApplier(englishInflector));
mapper.PatternsAppliers.Merge(new OneToManyKeyColumnApplier(relationalMapper));
mapper.PatternsAppliers.Merge(new ManyToManyColumnApplier(relationalMapper));
mapper.PatternsAppliers.Merge(new ManyToManyKeyIdColumnApplier(relationalMapper));

So not a lot of code and settings. Also this assembly contains a lot of other very nice patterns for example ManyToManyPluralizedTableApplier after applying it table name for joining products and categories becomes  CategoriesToProducts. Just beautiful Smile.

Here is the source code for this post

So use ConfOrm!

15 comments:

  1. After first two paragraphs I wanted to give up and write in russian :)

    ReplyDelete
  2. LOL! please continue in English, your posts will be useful even out Russia.
    Thanks to contribue.

    ReplyDelete
  3. Btw.. Have a look to CoolColumnsNamingPack and Merge it directly instead applier by applier ;)

    ReplyDelete
  4. Thank you Sly.
    It is the very good article.
    Eexample is very useful.
    We`ll used it for next project.
    Thank you.

    ReplyDelete
  5. Fabio, thanks! I will certainly have a closer look at CoolColumnsNamingPack.

    ReplyDelete
  6. Wow, this is some kind of event that can be compared to the beginning of the new Era =)Fabio, it is very nice to see you here, Sly has DDOS'ed my Skype with a messages saying that you've commented his blogpost.

    ReplyDelete
  7. отлично Андрей, очень интересно - спасибо болшое ;-)

    ReplyDelete
  8. Sly, in the sources you can find the prj ConfOrm.UsageExample, have a look to Packs composition... or even better have a look to the various examples you can find there.
    If you need an hand to understand something let me know... the price to pay will be a blog-post ;)

    ReplyDelete
  9. 2 Restuta

    how comes single Sly could do a Distributed DOS attack?

    ReplyDelete
  10. Restuta just over reacting on a single message in skype :)

    ReplyDelete
  11. You mean on a whole bunch of them?

    ReplyDelete
  12. This comment has been removed by the author.

    ReplyDelete
  13. 2 COTOHA, Who said "single", he asked friends to help him?

    ReplyDelete
  14. Hi Sly.

    There are some question about creating mappings.
    Colud you please review tables in DB Orders and Users. There are two duplicated keys in the Orders table: User and UserId.
    P.S. Sorry for my English

    ReplyDelete