In parts 1- 7 of the article series, I completed coding various types of associations using NHibernate.
- Object Relational Mapping (ORM) Using NHibernate - Part 1 of 8
- Object Relational Mapping (ORM) Using NHibernate - Part 2 of 8
- Object Relational Mapping (ORM) Using NHibernate - Part 3 of 8
- Object Relational Mapping (ORM) Using NHibernate - Part 4 of 8
- Object Relational Mapping (ORM) Using NHibernate - Part 5-A of 8
- Object Relational Mapping (ORM) Using NHibernate - Part 5-B of 8
- Object Relational Mapping (ORM) Using NHibernate - Part 6 of 8
- Object Relational Mapping (ORM) Using NHibernate - Part 7 of 8
his is the last of the eight-part article series. In this article, we clear the question from the end of the first article, "How do we manage a persistent object across sessions?". The background for the article is very important since it paves the way and introduces important topics required for understanding the discussions here.
Background
All ORM applications use a persistence manager for functionality like database writes, reads, and queries. In NHibernate, it is done by interfaces called Session, Transaction, Criteria, etc. Each session must first open a transaction, and all activities on objects are within this boundary of transactions (saying it as a transaction is a highly simplified way of representing it. In ORM, it is generally referred to as a unit of action and not necessarily a transaction, but you will get an idea with the word "transaction," and saves me from going into an explanation of "what a unit of action" is, which in itself is an exhaustive & interesting topic in ORM and is definitely not necessary for the consumption of ORM software for application development but vital for developing an ORM library like NHibernate.).
Each session is said to be associated with a PersistenceContext. PersistenceContext provides functionality like maintaining a unique object identity (called identity scoping), repeatable reads, avoiding a recursive load of objects in a graph, automatic transactional writes, dirty checking, etc. People who have worked with ORM code will immediately know what this Persistence Context means just by reading the functionality it offers. Yes, it is the good old IdentityMap. For the rest, I explain the idea here, which is essential to understand. Note that the idea expressed here is based on our previous experience in the development of an ORM library and not NHibernate specifically, but the idea is almost the same for most ORM libraries.
As said earlier, for ORM software, the first step is fixing object identity for persistent objects in a way that it is uniquely matched to a database row. The next step is ensuring that the identity is unique and that only one persistent object exists representing a particular database row. This avoids ambiguity. So what is usually done to ensure this object's uniqueness is an in-memory hashtable is used with the database primary key as the "key" field of the hashtable and the persistent object as "Value". Whenever ORM software does a lookup of a persistent object in the database while executing a query or gets it by id (i.e, the primary key value), it first does a lookup for the persistent object in this hashtable using the "primary key," which is the key field for the hashtable. If it exists, it just returns the object from the hashtable. Otherwise, the ORM software creates an object based on values obtained by executing the query against a database and adds it to the hashtable, and then finally returns the object to the client code. Every persistent object used by the client code is stored in this hashtable. This is the first-level cache for the ORM software. When you ask for an object repeatedly, only the first time, it is queried against the DB. It is subsequently gotten from this cache or hashtable. This is called a repeatable read. The main thing is where you keep this hashtable. If you keep this hashtable at the process level and store all objects of a process there, then you need to synchronize access to the hashtable from multiple threads. So the general idea is to keep this hashtable at the thread level, and all persistent objects modified in a session and transactions within this thread are maintained inside this hashtable per thread. This is named a persistent context cache (more or less gives a rough picture of how the ORM library is developed). The next functionality offered by the persistent context is dirty checking. The name dirty checking is self-explanatory. It means you find whether an object is modified or not within the scope of 1 transaction. ORM software uses two ways to do that: 1. By storing a snapshot of a persistent object separately at the start of the transaction and comparing it at the end of the transaction, 2. Keep an IsDirty flag and set it if an object is modified. NHibernate must use the first method of DirtyChecking, obviously, because we don't set any flags while modifying persistent objects, and we don't inherit objects from a well-defined NHibernate interface which would be necessary for the second method. So what is the use of dirty checking? At the end of a transaction, NHibernate will synch the changes of all modified dirty persistent objects to the database if it is a successful transaction. You don't have to do anything. Persistent objects are managed by NHibernate. The snapshot method is preferred by a sophisticated library like NHibernate because you can fine-tune the SQL generated for updates to the database to include only fields that were actually modified instead of all the fields for the object. So now we are familiar with the persistent context. This persistent context and its cache is associated with each session separately. The diagram in Figure 1 gives a rough idea of the thread-level persistent context cache.


Gowtham RajamanickamPosted Mar 28, 2015, 12:29 PM
soooperb