NHibernate

My talk at #kievaltnet about NHibernate internals

December 4, 2011 Conferences, NHibernate, Presentation, Success 2 comments

Friday I’ve been in Kiev, the capital of Ukraine. At the beginning of the day me with my wife visited couple of shops to buy some special things my wife makes. And than we went to have a good sit in small restaurant till 7 PM. I had to finish up my presentation…
Recently I’ve mentioned that I will be speaking at Kiev ALT.NET. So this post is about it.

Kiev ALT.NET

Kiev ALT.NET is great group of smart people willing to learn interesting things in .net but maybe from deeper standpoint than standard .net user groups do. I’ve been having good conversations in twitter with @chaliy and once we met at UnetaPlus in Kharkiv where he invited me as speaker to the @kievaltnet. Peliminary we agreed on something about NHibernate.

The topic

I knew that I have to prepare something interesting on NHibernate. But what? There are dozen of articles on it, there are many videos available. Topic just came itself. You might know that I’ve been working with NH for long time already and that I’ve written something similar to ORM so I decided that getting some insight into NHibernate’s guts would be really interesting.

Presentation delivery

So before 7 PM I got to the Ciklum office (building on the left). Landscapes from the 20th floor are astonishing, especially at night.
image
Not sure if I was enough prepared, but at least I felt that guys were listening to me very-very attentively. Some of them twitted simultaneously (@alexbeletsky, @skalinets, @korneliuk) and had good laugh. At least I invented term “swiss breakpoint” (aka. conditional breakpoint with cross).
image
More photos can be seen on facebook’s page here of the Kiev ALT.NET group.
Also I tried to joke much, but it didn’t go as well as I expected it to, guess because of sleepless night and general tiredness. Also I spoke with accent (as per them o_O. Never thought I have any kind of accent of my native language).

Presentation itself

View more presentations from Andriy Buday.
I would like to thank all guys, who came to listen to me and other presenters. Thanks for having me at Kiev ALT.NET. It had been great time and I would like to be there once again despite reason (to speak or to listen).


2 comments


Upgrading to higher version of NHibernate w/ FluentNH

August 23, 2011 NHibernate No comments

“How much would it take?” – Yeah, it is interesting question, which we gave to ourselves being maybe 3rd year of developing projects based on NHibernate. We took quick look and from top of the head it looks like it would take a lot of time, because FluentNhibernate has changed syntaxes, because there might be something not working after changes, etc.
You know what? I was able to change version of NHibernate and make it working for us within 25 minutes.
It just proves known statement about giving estimates: Judge as last resort!” Better compute and much better count if applicable.
So what is needed to be changed when you are upgrading to higher version of NHibernate w/ FluentNHiberante (from 2.0.0.4000 to 3.1.0.4000):
  1. Download compatible versions of NH and FNH. Usually FNH is step behind. (see release notes)
  2. Update references of your projects if you have folders for versions of 3rdParties.
  3. Update fluent initialization of NH with adding proxyfactory, like below:

var configuration = new Configuration();
var properties = new Dictionary<string, string>();
properties.Add(“proxyfactory.factory_class”, “NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle”);

4. Also you would need to reference NHibernate.ByteCode.Castle in your starting project.

5. Update fluent mapping with removing different noise code like below (if you are below 1.0 version):

image

We had about 250 mapping files so “Ctrl+H” had to be used a lot.
6. Run your application and see if you don’t have any issues.

So, long story short, updating to higher version of NH is not painful. It is still not clear if it has big impact or not, especially for big project.
If we decide to upgrade I will let you know if testing shows big impact.


No comments


Distributed transactions with NHibernate

January 31, 2011 NHibernate No comments

Most of our current NHibernate saving methods look like below:

        public void SaveCustomer(CustomerEntity customer)
        {
            var transaction = GetActiveTransaction();

            transaction.Begin();
            try
            {
                // some code
                Session.SaveOrUpdate(customer);

                transaction.Commit();
            }
            catch (Exception e)
            {
                transaction.Rollback();
                throw e;
            }
        }

this works great if you need to save just Customer or just Vendor. But in recent time we got kindof challenge to save Customer and Vendor at once in scope of one transaction for piece of functionality, and at the same time method should work for another piece of functionality.
For this we change our methods as following:

        public void SaveVendor(VendorEntity vendor)
        {
            using (var scope = new TransactionScope(TransactionScopeOption.Required)) // if there is no transaction scope, new will be created...
            {
                using (var transaction = Session.BeginTransaction())
                {
                    // some code
                    Session.SaveOrUpdate(vendor);

                    transaction.Commit();
                }
                scope.Complete();
            }
        }

Now we can utilize our methods higher in the call stack:

        public void SaveBunchOfInformationAtOnce(CustomerEntity customer, VendorEntity vendor)
        {
            try
            {
                using(var scope = new TransactionScope(TransactionScopeOption.RequiresNew)) // always new transaction will be created
                {
                    CustomersRepository.SaveCustomer(customer);

                    VendorsRepository.SaveVendor(vendor);

                    scope.Complete();
                }
            }
            catch(Exception e)
            {
                // log errors...
                throw;
            }
        }

This all works just fine both for existing method calls and for new one. Hope it helps.
Next thing that I might need to put into place is to distribute transactions through WCF services. That should be fun.


No comments


Allow set in your POCO or write crappy resolvers for AutoMapper or what?

December 20, 2010 AutoMapper, NHibernate 2 comments

In my project we are using NHibernate and Automapper to automatically map heavy database objects to light DTO object that we send across the wire. This works just fine, unless you have to map light object received to the POCO class.

Accordingly to all normal recommendations and just good common sense. You would not expose properties of your database objects with setter. Because ORM should fetch object graph in consistent state. And when you want to set Customer for Order you would probably use SetCustomer() method for better visibility and in

    public class Order
    {
        private Customer _customer = new Customer();
        public virtual int OrderId { get; set; }
        public virtual DateTime OrderDate { get; set; }
        public virtual Customer Customer { get { return _customer;}}
    }

and in mapping you would write something similar to this:

    public class OrderMap : ClassMap
    {
        public OrderMap()
        {
            WithTable("`Order`");

            Id(x => x.OrderId);
            Map(x => x.OrderDate, "OrderDate");

            References(x => x.Customer)
                .Access.AsCamelCaseField(Prefix.Underscore)
                .WithForeignKey("CustomerId");
        }
    }

as you can see, we set value for Customer using reflection deep inside of NHibernate. Also this approach ensures us that newly created Order will have default Customer object. But when we come to mapping OrderModel, which looks like below:

    [DataContract]
    public class OrderModel
    {
        [DataMember]
        public virtual int OrderId { get; set; }
        [DataMember]
        public virtual DateTime OrderDate { get; set; }
        [DataMember]
        public virtual CustomerModel Customer { get; set; }
    }

OrderModel.Customer simply doesn’t map to Order.Customer, since AutoMapper doesn’t have access to write into that value. Sadly, but AutoMapper doesn’t have any convention like NHibernate                 .Access.AsCamelCaseField(Prefix.Underscore), which means that it will look for _customer.

And now! AutoMapper is much smarter than NHibernate. You don’t need any conventions you can simply put private set and you are good! So I did:

    public class Order
    {
        private Customer _customer = new Customer();
        public virtual int OrderId { get; set; }
        public virtual DateTime OrderDate { get; set; }
        public virtual Customer Customer
        {
         get { return _customer;}
         private set { _customer = value;}
        }
    }

Honestly I wouldn’t write this post if I had knew about this possibility before I started writing it. But since I wrote more than half of what you see I decided to finish the story. Enjoy or blame me. Anyway for myself I took following: sniff around features and components you are using, some of them have better ideas than others, your task is to absorb the best!


2 comments


Understanding FetchMode

August 29, 2010 NHibernate No comments

Few days ago I’ve faced with duplication of data in XML we send to vendors and it leaded my to basic understanding how fetching works within NHibernate.

Database

So to make things clear we will start with ever simplest database layout and few datarows as on picture below:

I’m using following code to test our activities.

        private void FetchCustomerUseOrders(ISession session, FetchMode fetchMode)
        {
            var criteria = session.CreateCriteria(typeof(Customer))
                .SetFetchMode(“Orders”, fetchMode)
                .Add(Restrictions.Eq(“CustomerId”, 10));
            var customers = criteria.List<Customer>();
            Console.WriteLine(customers[0].Orders.Count);
        }

It fetches Customer with passed in FetchMode and then uses Orders to examine how lazy loading works.

Then I’m calling method for each of the FetchMode in separate sessions like below:

            using (var session = sessionFactory.OpenSession())
            {
                FetchCustomerUseOrders(session, FetchMode.Default);
            }
            using (var session = sessionFactory.OpenSession())
            {
                FetchCustomerUseOrders(session, FetchMode.Eager);
            }
            using (var session = sessionFactory.OpenSession())
            {
                FetchCustomerUseOrders(session, FetchMode.Join);
            }
            using (var session = sessionFactory.OpenSession())
            {
                FetchCustomerUseOrders(session, FetchMode.Lazy);
            }
            using (var session = sessionFactory.OpenSession())
            {
                FetchCustomerUseOrders(session, FetchMode.Select);
            }

Mapping of the Customer

            HasMany(x => x.Orders)
                .Access.AsCamelCaseField(Prefix.Underscore)
                .WithKeyColumn(“Customer”)
                .FetchType.Join()
                .LazyLoad();

Generated SQL-s

NHibernate can generate two types of fetching: either join or either separate select statements. So our code generated three join statements for Default, Eager, Join. Also two calls to database with two selects for the Lazy and Select. So all FetchMode except of Default are overriding our Customer mapping.

Join SQL

There is one thing you should remember about such kind of fetching – you will get duplication of the entities in your collections. You should apply joining when you are going to have some specific restrictions in your query.

Duplication of entities:

On the picture above you see two customers, which are the same references and represent same customer with same id = 10. To eliminate this issue you should apply one of the fixes: use distinct, use subquery or filter entities in client code. This article should make this more clear.

My recommendation is never use “.FetchType.Join()” in your One-To-Many relations as I did that. Better let NHibernate do it by default. Nhibernate applies Join to Many-To-One relations and Select to One-To-Many.

In my case better use following:

            HasMany(x => x.Orders)
                .Access.AsCamelCaseField(Prefix.Underscore)
                .WithKeyColumn(“Customer”);

The less you write code – the less mistakes you do. :)

Two SELECT-s

This type of query is generated if you have Select() fetch type. If you have LazyLoad in your mapping second select will be executed only on accesing of the Orders property of Customer. In other case (Not.LazyLoad) it will be executed immediately on fetching Customer.

Hope this brings some light. At least for me it does.


No comments


Lviv .NET User Group: My presentation on NHibernate

July 15, 2010 LvivNetUserGroup, NHibernate, Presentation No comments

Hello, as many of you know yesterday I spoke to NHibernate at local .NET User Group.

I won 20 beers, because we’ve got > 30 attendees

It was group’s 4-th meeting and it went extremely well. Above 40 people participated and for me it was biggest audience I ever had to talk to during one hour or so. For another speaker – Derik Whittaker – I’m sure that this is not biggest audience he had, but maybe the biggest foreign language speaking audience. If I’m wrong please correct me.

Audience asked questions

People were asking me lot of questions and I tried to answer quickly and easily, but keeping in mind that I should continue and be in time, since it is bad practice to overtime speech.

I asked questions

To my own surprise flow of delivering this presentation was so smooth and harmonic with audience. Asking people simple questions, making them shaking their hands and keeping attention, because maybe another time I’ll ask exactly someone from them.

I’m proud for my presentation skills

From day to day I become better in my ability to talk easily to technical audience. This time I’ve got the most sophisticated audience I ever had. They all had good experience working on different projects. So it was not like talking to university guys, who are very “green” in their understanding of technology and how things should look like.

Presentation itself

You could take a look at my presentation below.

View more presentations from Andriy Buday.

Not enough time to finish my second demo

For my second demo I allocated about 20 minutes, but it turned out, that I got about 10 and also talking to it and coding takes longer than sitting with my own keyboard and typing it at light speed. So sorry guys for not showing what I planned there.
What was planned and I did not show is: demoing lazy loading, chasing, complex Criteria API, and maybe the interesting – implementing own UnitOfWork and NHibernate repositories, approaches to build domain model with NHibernate.
BTW: I’m also going to have another blog post on NHibernate itself.

Really looking forward to get your feedback! Please leave your comments!


No comments


Using NHibernate Profiler with Unit Tests

July 5, 2010 NHibernate, QuickTip, UnitTesting No comments

Today, I’ve been writing few methods for my DAL classes, of course, I decided to have one or few integration unit tests that hits database and see actual SQLs with NHibernate Profiler.

So in couple of minetes I’ve got unit tests that had following line in the beggining of each:

 HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize();

if you don’t know, this line attaches your execution code with NHibernate Profiler, so I’m able to see SQLs NHibernate generates.

When I run bunch of unit tests in my testing file, I’ve got strange picture with duplicating of queries for each test with arithmetic progression. And N+1 problem, but hold on, I’m sure that I did everything through joins.

Reason is that profiler appends to my code on each new test run and that is why it start thinking that I have multiple selects to get list of something.

Solution, which I would recommend as pattern for writing Unit Tests with NHibernate Profiler is following:

        [SetUp]
        public void SetUp()
        {
            HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize();
        }
        [TearDown]
        public void TearDown()
        {
            HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Stop();
        }


No comments


NHibernate: Projections.RowCount()

February 19, 2010 NHibernate, QuickTip No comments

 What do you see to be wrong with this code?

        public bool RuleExists(string ruleName, string documentName)
        {
            var result = Session.CreateCriteria(typeof(Rule)“r”)
                //some aliaces 
             
                .SetProjection(Projections.RowCount())

                .Add(Restrictions.Eq(“r.Name”, ruleName))
                //other restrictions
                .List();

            return result.Count > 0;
        }


At first I did not see any issues with it so I copied it and changed a bit for my another query. But current method is wrong. I discovered this with UTs.

First, Projections.RowCount(generates COUNT(*) in select statement.

This is query, which I got from my new Unit Tests: RuleExists_HitsDatabase_ThereIsNoRule.

SELECT count(* ) AS y0_
FROM   TBL_RULE this_
       INNER JOIN — some joins here
     
WHERE  this_.NAME = ‘absolultely_incorrect_rule_name’ /* @p0 */
       AND — other conditions 

Result of this query is number of rows like on picture below:

So, verification return result.Count > 0is absolutely incorrect.
I’ve chagned it to return (int)result[0] > 0;

Moral:
Do not be lazy to write Unit Tests both for success and failure sceneries.


No comments


Few NHibernate hints on Query Criteria

February 15, 2010 NHibernate, QuickTip No comments

ORDER BY


To add “order by” to your criteria you need this statement.
.AddOrder(Order.Asc(“Priority”))

TOP


To add “top 10” to your criteria you need this statement
.SetMaxResults(10)

Criteria

So code about which I’m talking could look like:

        public IList<Customer> FetchTopPriorityCustomers()
        {
            var result = Session.CreateCriteria(typeof(Customer))
                .SetFetchMode(“CustomerStatusType”FetchMode.Eager)
                .Add(Expression.Eq(“CustomerStatusType.CustomerStatusTypeID”, (Int32)CustomerStatusType.Created))
                .SetResultTransformer(new DistinctRootEntityResultTransformer())
                .AddOrder(Order.Asc(“Priority”))
                .SetMaxResults(10)
                .List<Customer>();
            return result;
        }

SetResultTransformer or “Why did I get 5 results instead of 10?”

So you expect to have top 10 priority Customers with status Created.
In scope of my current task it was needed to add priority to this query, so I decided to unit test it of course.
In Debug I found that there are actually 5 results in resulting collection.

That is because generated SQL generates result which contains duplicated CUSTOMER_IDs, that is because I have join-s there. But then why did not I get 10 duplicated Customers? Because query has ResultTransformer which is applied after SQL has been ran. (That is 100% since I took a look at generated SQL via NHibernateProfiler).

So .SetResultTransformer(new DistinctRootEntityResultTransformer()) is removing of all duplicated entries of my root entity (Customer).

Good explanation to this you can find here.


No comments


Save entity with assigned ID, not generated by NHibernate.

February 3, 2010 NHibernate No comments

I want generate INSERT which include my Primary Key (not generated) by NHibernate. How to map Id column for this?

I have table CUSTOMER where CUSTOMER_ID is primary key.

Table

  

Code:

CREATE TABLE [CUSTOMER](
    [CUSTOMER_ID] [int] NOT NULL,
    [START_DATE] [varchar(30)] NOT NULL,
CONSTRAINT [PK_CUSTOMER] PRIMARY KEY CLUSTERED ( [CUSTOMER_ID] ASC …..

Mapping

Code:

public class CustomerMap : ClassMap<Customer> {
    public CustomerMap()
    {
        WithTable(“CUSTOMER”);
        Id(x => x.CustomerID, “CUSTOMER_ID”);
        Map(x => x.Name, “NAME”);
    }
}

I need to handle assigning of the CustomerID property manually. For
example I created new Customer with CustomerID = 777 and Name
= “Andriy Buday”
.

When I call method Session.Save(customer);
I want NHibernate to generate me SQL like this:

  

Code:

INSERT INTO [CUSTOMER] ([CUSTOMER_ID] ,[NAME]) VALUES (777,‘Andriy Buday’)

Unfortunately I’m getting errors.

Main issue here is that Nhibernate tries to generate ID for me. But I want to save my entity exactly with 777.

Solution

So I need to manually setup my ID property with adding GeneratedBy.Assigned();
Like here:

Code:

Id(x => x.CustomerID, “CUSTOMER_ID”)
      .GeneratedBy.Assigned();


No comments