Weeks ago we decided to upgrade to NHibernate 2.1.2
to be beneficiary of LINQ-to-NHibernate and other new features of last version of NHibernate. After introducing LINQ technology in .NET 3.0 many people were thinking the lack of a LINQ provider for NHibernate until when Ayende Rahien introduced the existence of LINQ-to-NHibernate.
My colleague Masoud and I started to replace a group of old NHibernate queries with LINQ-to-NHibernate queries. We progressed the task quickly and finished the entire task in few days. But very soon realized that writing LINQ-to-NHibernate queries is not as easy as we thought. Our queries were based on my knowledge of LINQ-to-Objects but many features working in LINQ-to-Objects was not working in LINQ-to-NHibernate. For example short circuit evaluation was not working. We tried to solve problems specially with help of StackOverflow. And here is some of encountered problems and their solution:
1. (TargetInvocationException): Exception has been thrown by the target of an invocation., (NullReferenceException): Object reference not set to an instance of an object., Occurs when a compare in LINQ throws an exception, this exception is wrapped in a TargetInvocationException exception and rethrowed. Like: l.Sender.Role.Contains(senderRoleSearch.Trim()) when senderRoleSearch == null
2. Working with Enums is a bit strange. If you have a mapping like this:
then you will encounter some odd errors like:l.LetterType == LetterType.Internal results in “(QueryException): Type mismatch in NHibernate.Criterion.SimpleExpression: LetterType expected type System.Int32, actual type Faraconesh.EnterpriseAppUnits.OfficeAutomation.BusinessEntities.LetterType,. In this case you should remove type=”int” from the mapping. solution. For more information go here.
3. When you have such a query:
var q=from l in session.Linq<Letter>
where crit == null ? true : l.Subject.Contains(crit.Trim())
select l;
You will probably encounter with “null object reference” because LINQ has not short-circuit evaluation. For more info go here and here.
4. Dynamic query:
While using nulls and nullables is not possible due to case 3 (above), You can use dynamic queries like this:
var q = from l in session.Linq()
select l;
if (serialNumberSearch != null)
q = q.Where(l => l.SerialNumber == serialNumberSearch.Trim());
5. Can not call methods: We were not able to find a solution.
6. Subqueries does not work. Here is a our work-around.