December 4, 2011 Conferences, NHibernate, Presentation, Success 2 comments
December 4, 2011 Conferences, NHibernate, Presentation, Success 2 comments
August 23, 2011 NHibernate No comments
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):
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.
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.
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!
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.
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:
Mapping of the Customer
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:
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.
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.
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!
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:
February 19, 2010 NHibernate, QuickTip No comments
What do you see to be wrong with this code?
.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.
Result of this query is number of rows like on picture below:
So, verification return result.Count > 0; is 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.
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:
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.
February 3, 2010 NHibernate No comments
I have table CUSTOMER
where CUSTOMER_ID
is primary key.
Table
Mapping
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:
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: