What are the most common mistakes and anti-patterns NHibernate user programmers make? Please explain why those are bad practices or give link to resource for further reading.
For example:
- One anti-pattern common for new NHibernate programmers is to use identity/native POID's instead of ORM style onces. Read more here...
-
1You can find some of the common mistakes here: NHProf AlertsVahidN– VahidN2011年08月11日 07:42:55 +00:00Commented Aug 11, 2011 at 7:42
-
1Also there are some valuable posts here about NHibernate PitfallsVahidN– VahidN2011年08月11日 07:45:39 +00:00Commented Aug 11, 2011 at 7:45
4 Answers 4
My personal "frequently explained" issues:
Anti-Patterns
Messing around with detached objects (SaveOrUpdate or Merge plus some messy code) instead of using DTO's. The more complex the entities are, the messier the code is. (It also means that it works quite well with trivial entities.) Ayende also calls it the Stripper Pattern and explains the encapsulation issue.
Not understanding persistence ignorance and writing NH applications as when using explicit SQL. Symptom of that: calling Update after changing an object, wondering why changes are persisted even if Update had not been called, wondering how to avoid changes to be persisted.
- I tried to explain it in this SO answer
- Read how flushing works in the reference documentation.
- A blog post by kurtharriger who is criticizing exactly what is actually one of the main features (as a prove that it is a common misconception about NH)
Not understanding transactions and the unit of work pattern. Frequent anti-patterns: implicit transactions, session-per-operation and session-per-application. Some more reading:
- Fabio Maulo: Conversation-per-Business-Transaction
- On nhforge.org: Effective NHibernate Session management for web apps
Using NH events to put application logic in (eg. change tracking in insert and update triggers)
Create one class per table. Some people don't understand OOD, others don't understand relational design.
Mistakes
use of one-to-one instead of many-to-one. I tried it to explain in this answer.
Using join fetch in combination with SetMaxResult. My latest answers related to that topic:
- Why doesnt NHibernate eager fetch my data (with some more notes about side effects in the comments)
- Hibernate - How to make associations eager
- NHIbernate 1.2 And Lazy Loading
- Pagination with Hibernate criteria and FetchMode.JOIN
Writing self changing entities. When an entity doesn't exactly return the value that had been set by NH, it is considered dirty and gets updated in every session. For instance: replacing the NH persistent collection in a property setter.
IList<Address> Addresses
{
get { return addresses; }
// will cause the addresses collection to be built up from scratch
// in the database in every session, even when just reading the entity.
set { addresses = new List<Address>(value); }
}
int Whatever
{
// will make the entity dirty after reading negative values from the db.
// this causes unexpected updates after just reading the entity.
get { if (whatever < 0) return 0; }
set { whatever = value; }
}
May be more is following.
-
2+1: You should add "Not using Unit of Work pattern" and "One session per application" to your list imho.Falcon– Falcon2011年08月12日 07:41:49 +00:00Commented Aug 12, 2011 at 7:41
-
@Falcon: yeah probably. It's a general "not understanding transactions" problem. The unit of work is a bit covered by persistence ignorance. Although they are completely different concepts, they result in the same patterns.Stefan Steinegger– Stefan Steinegger2011年08月16日 10:33:02 +00:00Commented Aug 16, 2011 at 10:33
The "Select N+1 Problem".
This is where you end up executing A select for each entity you want to manipulate (N), and a select to get the list of entities (+1), instead of a single select of all entities and their attributes.
- Too many abstractions
- Not using Automappings with
FluentNHibernate
-
The first point is a little vague, but in case you are referring to silly notions such hiding ISession behind a "Repository" or "DAO", I agree.chris– chris2014年01月07日 14:54:08 +00:00Commented Jan 7, 2014 at 14:54
-
1The second point however is nonsense. There are good reasons why we often want to have fine grained control over the physical data model and be able to decouple that from the domain model. After all, that's the point of the "M" in "ORM". Using automappings (while useful in simple scenarios) defeats that. Besides, there is also the issue of integration legacy database schemas, for which automapping is useless.chris– chris2014年01月07日 15:00:53 +00:00Commented Jan 7, 2014 at 15:00
-
I use the inbuilt by code convention based mapping. It handles a great swath of crap I would otherwise have to repeat. However it still provides the freedom to but entity specific customisation that are layered over the mapping generated by convention. Its super helpful.Sam– Sam2014年02月03日 03:11:27 +00:00Commented Feb 3, 2014 at 3:11
Trying to abstract it out so that you can switch to Entity Framework (or something else) at a later date.
This is much, much harder than most people who attempt it realise. There are numerous differences between the two that can trip you up in ways that can be quite subtle at times. It's also very uncommon for it to actually be needed in the end -- so much so that you can be meticulously trying to implement it for years before discovering that your approach is all wrong.
Also, it restricts you from using a whole lot of NHibernate's useful and important features such as second-level caching, interception, concurrency management, change tracking, prefetch queries and so on.
If there really were a valid need to switch between NHibernate and Entity Framework, there would be an actively developed project to support this on GitHub (perhaps something in a similar vein to CommonServiceLocator) with numerous contributors and pull requests.