I heard from some peoples that bidirectional association is evil. I don’t know where them sneezed it from. I am not going to take a side and discuss it here. I am going to tell you that your choice have influence on NHibernate behavior and your code’s performance.
Lets start with bidirectional association.
Order references a collection of order lines and each order line references it’s order. And I map collection as <bag> with inverse=true option.
Lets try to add a new order line to an existing order.
Take a look on what is going in the database
Now lets see what happens when we use model with unidirectional association. Little changes to code and mapping. And that’s what we got in the database.
Dah!? What’s going on here?
The second query ignoring that collection mapped as a bag and goes to bring us already existing order lines. Seems like a bug.
Third query forgot to set reference from the new order line to the order.
And fifth query fixes that mistake. And that update will be executed for each order line.
It’s annoying. So, finally, we have at least two unnecessary queries when we decide to use unidirectional association.
I don’t know why and what was going in the heads of NH programmers when them coded it (no offence), but that is what we have and we will use it for the win! Just know your tools and make right decisions.
Lets start with bidirectional association.
public class Order{ public virtual Guid Id { get; set; } public virtual int Version { get; set; } public virtual DateTime OrderTime { get; set; } public virtual ICollection<OrderLine> OrderLines { get; set; } } public class OrderLine{ public virtual Guid Id { get; set; } public virtual Order Order { get; set; } public virtual string ProductName { get; set; } public virtual decimal Price { get; set; } public virtual int Quantity { get; set; } }
Order references a collection of order lines and each order line references it’s order. And I map collection as <bag> with inverse=true option.
Lets try to add a new order line to an existing order.
using (var session = sessionFactory.OpenSession()) using (var tx = session.BeginTransaction()) { var order = session.Get<Order>(id); order.OrderLines.Add(new OrderLine { Order = order, ProductName = "Product 1", Price = 9.99M, Quantity = 15 }); tx.Commit(); }
Take a look on what is going in the database
SELECT order0_.Id as Id0_0_, order0_.Version as Version0_0_, order0_.OrderTime as OrderTime0_0_ FROM Orders order0_ WHERE order0_.Id=@p0 INSERT INTO OrderLines (OrderId, ProductName, Price, Quantity, Id) VALUES (@p0, @p1, @p2, @p3, @p4) UPDATE Orders SET Version = @p0, OrderTime = @p1 WHERE Id = @p2 AND Version = @p3Works as expected. The last query is for aggregate root versioning.
Now lets see what happens when we use model with unidirectional association. Little changes to code and mapping. And that’s what we got in the database.
SELECT order2x0_.Id as Id0_0_, order2x0_.Version as Version0_0_, order2x0_.OrderTime as OrderTime0_0_ FROM Orders order2x0_ WHERE order2x0_.Id=@p0 SELECT orderlines0_.OrderId as OrderId1_, orderlines0_.Id as Id1_, orderlines0_.Id as Id1_0_, orderlines0_.ProductName as ProductN2_1_0_, orderlines0_.Price as Price1_0_, orderlines0_.Quantity as Quantity1_0_ FROM OrderLines orderlines0_ WHERE orderlines0_.OrderId=@p0 INSERT INTO OrderLines (ProductName, Price, Quantity, Id) VALUES (@p0, @p1, @p2, @p3) UPDATE Orders SET Version = @p0, OrderTime = @p1 WHERE Id = @p2 AND Version = @p3 UPDATE OrderLines SET OrderId = @p0 WHERE Id = @p1
Dah!? What’s going on here?
The second query ignoring that collection mapped as a bag and goes to bring us already existing order lines. Seems like a bug.
Third query forgot to set reference from the new order line to the order.
And fifth query fixes that mistake. And that update will be executed for each order line.
It’s annoying. So, finally, we have at least two unnecessary queries when we decide to use unidirectional association.
I don’t know why and what was going in the heads of NH programmers when them coded it (no offence), but that is what we have and we will use it for the win! Just know your tools and make right decisions.
No comments:
Post a Comment