Connect

  • Connect with me

  • Wednesday, September 01, 2010

    NHibernate : Code First approach with fluent NHibernate

    Background

    In my previous post on Entity Framework, I had demonstrated the use of new EF code first CTP to create database schema based on domain model. I tried the same approach with NHibernate and this post is about the steps needed to get Fluent NHibernate and Automappings working together. The end result is similar to the last blog post. We are able to generate the database schema based on our domain model.

    Getting started with NHibernate

    I started off with the most basic example of NHibernate as per the steps listed in getting started with NHibernate. This was required to understand how does NHibernate work behind the scenes. Once I got the basic CRUD operations working with a single table, I needed a way to customize it to work for the parent child relationship. This is typically represented by Primary key-Foreign Key relationship at the database level.
    Once I understood the concept of mapping files, I decide to move onto the Fluent NHibernate which we use in our projects at office. This saves us a lot of time which we would have spent on writing the mappings in .hbm files. It has a very fluent interface and comes with a pluggable conventions. We can also use the Automappings feature to automatically map entities based on the conventions.

    Use Fluent NHibernate & Auto Mappings for code first development

    I am going to reuse the model classes from my previous example which are PickTrip and Label. The domain objects looks like
     public class PickTrip
        {
            public virtual int Id { get; private set; }
    
            public virtual string PickingZone { get; set; }
    
            public virtual DateTime DeliveryDate { get; set; }
    
            public virtual IList<Label> Labels { get; set; }
        }


     public class Label
        {
            public virtual int Id { get; private set; }
    
            public virtual PickTrip PickTrip { get; set; }
    
            public virtual string CustomeName { get; set; }
    
            public virtual string ShortOrderNumber { get; set;}
        }


    As part of creating the SessionFactory we need to set up the automappings as well as the conventions that we are going to use. One way to do this is to override the ShouldMap method by inheriting the DefaultAutoMappingsConfiguraation class as shown below.


    public class ExampleAutomappingConfiguration : DefaultAutomappingConfiguration
        {
            public override bool ShouldMap(Type type)
            {
                return type.Namespace == "FirstSolution.Domain";
            }
        }


    The above code will map all the domain entities from the namespace FirstSolution.Domain. Once that is done, we can also set the conventions for one to many and many to many relationships by means of cascade conventions as shown below.


    public class CascadeConvention : IReferenceConvention, IHasManyConvention, IHasManyToManyConvention
        {
            public void Apply(IManyToOneInstance instance)
            {
                instance.Cascade.All();
            }
    
            public void Apply(IOneToManyCollectionInstance instance)
            {
                instance.Cascade.All();
            }
    
            public void Apply(IManyToManyCollectionInstance instance)
            {
                instance.Cascade.All();
            }
        }


    While building the session factory object we need to bring in all the pieces together


    private static ISessionFactory CreateSessionFactory()
            {
                return Fluently.Configure()
                    .Database(MsSqlCeConfiguration.Standard.ConnectionString(@"Data Source =" + DbFile))
                    .Mappings(m =>
                              m.AutoMappings.Add(CreateAutomappings))
                    .ExposeConfiguration(BuildSchema)
                    .BuildSessionFactory();
            }





    The above method fluently configures a MS SQL CE database, it also adds the automappings to the configuration. It also exposes the configuration to create the schema of the database based on the model objects or entities as they are also called.


    The complete code related to this is available in the NHibernateHelper.cs file in the attachment.


    Lets try creating a new PickTrip and adding it to the database using NHibernate.


    PickTrip pickTrip = new PickTrip
                    {
                        PickingZone = "AM",
                        DeliveryDate = DateTime.Today,
                    };
    
                IList<Label> labels = new List<Label>
                    {
                        new Label { CustomeName = "Customer 1", ShortOrderNumber = "101", PickTrip = pickTrip },
                        new Label { CustomeName = "Customer 2", ShortOrderNumber = "102", PickTrip = pickTrip }
                    };
    
                pickTrip.Labels = labels;


    Once I have set the properties of PickTrip and associated labels with it, I can call a method on the PickTripRepository to persist it.


    public void Add(PickTrip pickTrip)
            {
                using (ISession session = NHibernateHelper.OpenSession())
                {
                    using (ITransaction transaction = session.BeginTransaction())
                    {
                        session.SaveOrUpdate(pickTrip);
    
                        transaction.Commit();
                    }
                }
            }


    Similar is the case for other use cases like Update, Delete and GetPickTrip which are demonstrated in the attached code.





    Conclusion



    Finally I managed to get the Automappings and Fluent NHibernate working together after spending almost about 2-3 days. Initially it was difficult to understand the concepts like session factory and conventions. Once the basics were clear it was quite simple.


    I would suggest instead of jumping directly to Fluent NHibernate and Automappings we should try the manual mappings so that we know how NHibernate works behind the scenes. Compared to the amount of time it took to set up code first approach running with Entity Framework 4 CTP this was definitely quite a bit of effort. I think setting up the session factory, adding auto mappings and conventions was a bit of an overkill.


    I would suggest to read the posts related to getting started with NHibernate and Fluent NHibernate very carefully. These links about Automappings, Fluent Configuration and Database mapping might be helpful.


    You can download the complete source code from dropbox.


    Until next time happy programming :)


    5 comments:

    1. Anonymous5:57 PM

      can i specify a varchar lenght for a field having just that without having to specify all other fields mappings? or i have to decide use automapping, fluent, or xml each by alone?

      ReplyDelete
    2. Check out AutoMappingOverrides, these let you specify fine grained control over mappings while taking advantage of automatic mappings. Nice article btw. Steve

      ReplyDelete
    3. Anonymous1:51 AM

      Mr Gule, please change the color scheme of the site, because it is mostly unreadable.

      ReplyDelete
    4. Anonymous8:55 AM

      Great post! It'll definitely help me setting up FluentNHibernate. I like how you provided links to the various resources that helped you out.
      One minor tidbit...the contrasts you used for the code examples makes it very difficult to read.

      ReplyDelete
    5. Nilesh

      This is WAY easier to use than NHibernate:
      https://www.kellermansoftware.com/p-47-net-data-access-layer.aspx

      ReplyDelete