Try fast search NHibernate

06 September 2010

ConfORM: Usage Examples

I have promised myself to no post often about ConfORM, instead I have started a new project, available with ConfORM’s sources, where I’ll show some usage examples with some explication.

So far there are few examples created under users requests. If you want see the code without download, it is available here.

Taking the opportunity of this post I would show you another success story:
It is about an “Inventory management and stock control” system composed by 65 entities/components where the persistence is managed using NHibernate 2.1.2. Because ConfORM uses a NHibernate 3 specific feature they can’t use ConfORM directly in the application, instead they are using ConfORM to generate XML mappings (soon, probably, they will use it directly with NHibernate 3). They can trust in ConfORM because they have, so far, 83 persistence integration-tests testing CRUD and expected cascades operations.

I can’t show you the domain-model but I can show you the whole mapping:

IEnumerable<Type> domainEntities = typeof (BaseEntity)
    .Assembly.GetTypes()
    .Where(t => typeof (BaseEntity).IsAssignableFrom(t) && !t.IsGenericType)
    .ToList();

var tablePerClassHierarchy = new[] {typeof (Movement), typeof (MovementDetail)};
IEnumerable<Type> tablePerClassEntities = typeof (BaseEntity)
    .Assembly.GetTypes()
    .Where(t => typeof (BaseEntity) == t.BaseType && !tablePerClassHierarchy.Contains(t))
    .ToList();

var orm = new ObjectRelationalMapper();

orm.TablePerClass(tablePerClassEntities);
orm.TablePerClassHierarchy(tablePerClassHierarchy);

orm.Exclude(typeof (Movement<>));
orm.Exclude(typeof (MovementDetail<>));

orm.ManyToMany<Product, Tag>();

var patternsAppliers =
    (new SafePropertyAccessorPack())
        .Merge(new OneToOneRelationPack(orm))
        .Merge(new BidirectionalManyToManyRelationPack(orm))
        .Merge(new BidirectionalOneToManyRelationPack(orm))
        .Merge(new DiscriminatorValueAsClassNamePack(orm))
        .Merge(new CoolTablesAndColumnsNamingPack(orm))
        .Merge(new TablePerClassPack())
        .Merge(new DatePropertyByNameApplier())
        .Merge(new MsSQL2008DateTimeApplier());

var mapper = new Mapper(orm, patternsAppliers);

mapper.Customize<Product>(
    cm =>
        {
            cm.Property(product => product.Code, pm =>
                                                     {
                                                         pm.NotNullable(true);
                                                         pm.Unique(true);
                                                     });
            cm.Collection(product => product.Tags, tagsm => tagsm.Cascade(Cascade.Persist));
        });

mapper.Customize<Role>(
    cm => cm.Collection(role => role.Functionalities, com => com.Cascade(Cascade.Persist)));

mapper.Customize<User>(cm => cm.Property(user => user.Nick, n => n.Unique(true)));

In this mapping you can see how compose ConfOrm.Shop.Packs and how map a whole domain in few lines ;-)

Are you ConfORM ?
They are!!!

13 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. I'm starting to feel sick when I see so many typeof() calls

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

    ReplyDelete
  4. Also I think that you trying to implement framework in place where frameworks are not applicable.

    ReplyDelete
  5. Facts says me something different. Personally I saw ConfOrm working in production with 5 not trivial proyects.

    ReplyDelete
  6. I have personally seen so much crappy "technologies" and "frameworks" in as many projects as you just can not imagine. And they worked. So your argument is irrelevant.

    Also, in my opinion, chasing a small number of lines of code - to chase a spherical horse in a vacuum: It is better to write 100 maintainable and testable lines of code than 1 unmaintainable and untastable.

    ReplyDelete
  7. ConfORM has 1300 tests about mappings.
    How you are testing your mappings ?

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

    ReplyDelete
  9. Hi, we are TDD fanatics. So first of all we write tests to our mappings via fluent-nhibernate's PersistenceSpecification and than write mappings using fluent-nh.

    Can you show me how I can apply TDD to ConfORM?

    ReplyDelete
  10. And what you think we are testing they are testing in their 83 persistence integration-tests ?

    ReplyDelete
  11. This is fabiolous! :-)

    I ever wanted to specify conventions for my mapping... It's allways the same thing. Mappings are repetitive code that really screams for beeing removed by higher abstractions like you did!

    But what made you choose LGPL over APL?

    ReplyDelete
  12. I wonder about a few choices you've made in the example there:

    - the orm.Exclude seem redundant given you've built the domainEntities list to exclude generic types already (!t.IsGenericType).

    - why are some "pattern appliers" named with a suffix "Applier" and others "Pack"? What's the difference? I'd call them patterns and that's it...

    ReplyDelete
  13. @kzu
    - Exclude is not only to exclude generics since, in NH, you can map generics. Exclude is to exclude implementations in the middle of a hierarchy.
    - a Pack is a Pack of patterns-appliers. A pattern-applier is A pattern-applier

    ReplyDelete