by andrei
3. October 2008 22:11
You can read about the purpose of this list and how to use it here.
Also, the list of resources is here.
- general implementation
B4 - concepts
- other orms
code & implementation
E1
E2 - things to avoid
- n+1 selects
Yet another classic problem is that of n+1 selects. Assume you fetch all Orders in the database and that OrderLines are Lazy Loaded. Then you touch each Order and its OrderLines. Then there will be a new SELECT issued for each Order's OrderLines. If you don't use Lazy Load, the problem will be smaller, but then you run the risk of getting into the problem just mentioned of fetching too much in some scenarios.
resources
B4 - reading way too much
A fifth is the "reading way too much" problem when too many complex types are read even though just a tiny amount of information is really needed. This is especially common if you haven't used a somewhat careful Aggregate design and haven't used Lazy Load.
resources
B4
- mapping
- discriminator
If we assume that Customer and Vendor inherits from Company, the mapping information could look like this:
<discriminator column="Type" type="AnsiString" length="8"
not-null="true" />
resources
B4 - inheritance
NHibernate supports all three different inheritance solutions, namely Single Table Inheritance, Class Table Inheritance, and Concrete Table Inheritance
resources
B4 - unsaved-value
resources
B4 - N:1
code & implementation
B4
resources
B4 - 1:N
code & implementation
B4
resources
B4 - value objects
NHibernate uses the word component for describing an Embedded Value
code & implementation
B4
resources
B4 - private fields
For example, you often expose something slightly different in your property get to what is stored, or you do some interception on get/set. In these cases, you need to map, for example, the private field instead.
code & implementation
B4
resources
B4
- entity lifecycle
resources
B4 - lazy load
If you do want to use (automatic) Lazy Load Fowler PoEAA with NHibernate, that's easily done
resources
B4 - scalar queries
Scalar queries are especially useful in situations where you find it too expensive to fetch complete Customer instances but want a more lightweight result, and you don't want to define a class.
Of course, the result won't be typesafe in this case, but you could use a variation, namely the one I talked about earlier in this chapter called report query (or a flattening query).
resources
B4 - report queries
the result won't have Customer instances, but CustomerSnapshot instances. For it to work, you need to provide a matching constructor on the Value Object (CustomerSnapshot in the previous case) and to mention CustomerSnapshot in a mapping file via an import directive
resources
B4 - transactions
Support for manual transaction control is pretty good in NHibernate. There are situations where you might be taken by surprise if you don't watch out (for instance, when you execute a query in the middle of a transaction, NHibernate will then Flush() changes to the database before executing the query). That's a tradeoff between querying not going "through" the cache or ordinary transaction control. The good news is that it's controllable by your code.
What you do is grab an ITransaction instance, which you can then use to make either a Commit() or Rollback() (Commit() will by default automatically do a Flush()).
I prefer to control the start and end of the unit of work in the consumer, outside of the repositories
resources
B4 - caching
Advanced caching is one area where NHibernate isn't really up to par when compared to Hibernate, but I think it's rapidly becoming better. On the other hand, to me that's not usually a big deal. There are many problems with second-level caching, so that option is often ruled out.
resources
B4 - unitofwork
NHibernate uses the Unit of Work pattern Fowler PoEAA as well, and again it's dealt with in the ISession. - query
- Criteria objects
- HQL
it's not table names but classes that are used in HQL
resources
B4 - joins
data is fetched from two tables, and there is no mention about that in the from clause (that is, there is no join). Of course, the mapping information is used to determine what needs to be done at execution time with the HQL query.
select o.Customer.Name, count(*) from Order o group by o.Customer.Name
resources
B4
- session
- clear
to clear the Identity Map from all instances
resources
B4 - evict
What you can do to force a database jump (instead of opening a new ISession) is to call Evict() on the instance by saying that you don't want the Identity Map to keep track of the instance any longer.
resources
B4 - flush
It is also important pointing out that the INSERT is delayed and won't happen when you say Save(), but rather when you say Flush().
resources
B4 - saveorupdate
I could have called SaveOrUpdate() instead, and then NHibernate would have decided on its own whether it should be an INSERT or an UPDATE. The information used in that case is the value of the Identity Field, and it's compared to what you indicated for unsaved-value in the mapping file ("00000000-0000-0000-0000-000000000000" in the case of Guids). If the Identity Field matches the unsaved-value, it's time for an INSERT; otherwise, it would be an UPDATE.
resources
B4
- identity
- don't set it manually
Normally, you would give Identity Fields default values, such as Guid.NewGuid(), but that's not a good idea if it's possible to avoid it when you use NHibernate because NHibernate uses the Identity Field values to determine if it should be an UPDATE or INSERT. If you provide a default value (unless you set it to unsaved-value, of course), NHibernate will always expect UPDATE if you don't explicitly provide guidance. (You can also use the version tag for signaling INSERT/UPDATE.)
resources
B4 - guid identity
In the case of the guid, you can generate it in all the layers, but it's recommended that you do it in the O/R Mapper
resources
B4
- repository
the consumer injects ISession instances to the repositories - interceptor
yet another NHibernate interface
To use a custom IInterceptor implementation, you provide it as a parameter when instantiating ISession
resources
B4 - validation
NHibernate has an IValidatable interface that will get calls by NHibernate at Flush().
But then I need to reference the nhibernate.dll in the Domain Model, so I prefer a solution like the one I used in Chapter 7, "Let the Rules Rule." I mean, I can use an IInterceptor
resources
B4 - concurrency
NHibernate deals with Optimistic Offline Lock if you add a <version> tag to the entities
resources
B4 - identity map
NHibernate uses an Identity Map on an ISession level.
resources
B4 - embedded resource
If you want the metadata to be within the assembly, don't forget to set the property of the XML file to be an Embedded Resource.
resources
B4 - generate database from mapping
I prefer to start with the Domain Model, then write the mapping files, and from that automatically generate the database from the mapping information
code & implementation
B4
resources
B4 - sessionfactory
What you then try to do just once per application execution is to set up a SessionFactory. The reason for not creating several is that the cost is fairly high. The SessionFactory will analyze all metadata and build up memory-based structures for that. As you might guess from its name, the SessionFactory is then used for instantiating new instances that implement ISession.
code & implementation
B4
resources
B4
You can find the entire list of techniques in progress in the Development base concepts category. Please feel free to leave any comments or suggestions which could make these lists more useful for everyone.
Also, if you are interested in learning these skills you can try the Developer training modules.
Enjoy programming!
I am putting together a set of concept lists for the main programming techniques, which should help developers learning or using them to be more efficient. Here are the techniques in progress:
Please feel free to leave any comments or suggestions which could make these lists more useful for everyone.
Also, if you are interested in learning these techniques you can try the developer training modules.
Again, please feel free to leave any comments or suggestions which could make the training modules more useful for everyone. We are having great results with them at Akcedo (so they really work), but they can always be improved. Also, if you would like to use the modules or are already using them and you want to discuss about the process feel free to comment and ask questions here.