When processing large amounts of data, you can usually improve performance by using an API that's closer to the bare metal, often times trading off some higher-level features in the process. In NHibernate, this high performance, low-level API is the stateless session.
Here we'll use a stateless session to update our movie prices.
Complete the Getting Ready instructions at the beginning of Chapter 4, Queries.
Stateless
to the QueryRecipes
project.Recipe
in the folder:using NH4CookbookHelpers.Queries; using NH4CookbookHelpers.Queries.Model; using NHibernate; using NHibernate.Linq; using System; using System.Linq; namespace QueryRecipes.Stateless { public class Recipe : QueryRecipe { } }
Recipe
class:protected override void AddData(ISessionFactory sessionFactory) { using (var session = sessionFactory.OpenStatelessSession()) { using (var tx = session.BeginTransaction()) { for (int i = 0; i < 1000; i++) session.Insert(new Movie() { Name = "Movie " + i, Description = "A great movie!", UnitPrice = 14.95M, Director = "Johnny Smith" }); tx.Commit(); } } }
Recipe
class:protected override void Run(ISessionFactory sessionFactory) { using (var session = sessionFactory.OpenStatelessSession()) { using (var tx = session.BeginTransaction()) { var movies = session.Query<Movie>().ToList(); foreach (var movie in movies) { UpdateMoviePrice(movie); session.Update(movie); } tx.Commit(); } } }
UpdateMoviePrice
method:static Random rnd = new Random(); static void UpdateMoviePrice(Movie movie) { // Random price between $9.95 and $24.95 movie.UnitPrice = (decimal) rnd.Next(10, 26) - 0.05M; }
Stateless
recipe.Using a stateless session, we create 1000 movies. Stateless sessions don't implement transactional write-behind, meaning that the SQL statements are not delayed until we commit the transaction. However, if we have turned on batching, they don't happen immediately either. Instead the insert statements are queued up and sent all together. If batching is turned off, these would be sent one at a time immediately with each call to session.Insert
.
Next, we fetch all of our movies from the database with the help of a query. These movies are detached; they are not associated with a session; entities can't be associated with stateless sessions. In this case, we load our entities with a query or the Get
method.
Since stateless sessions don't implement automatic dirty checking, we have to call session.Update
to save our changes to each movie.
A stateless session is essentially a stripped-down version of a standard NHibernate session. It doesn't use a first-level cache or perform automatic dirty checking and it doesn't support lazy loading. In fact, it doesn't even keep references to entities, which helps avoid memory leaks when processing thousands of entities. Cascading is ignored and you must explicitly insert, update, or delete each entity, one at a time. Stateless sessions also bypass the second-level cache, event listeners, and interceptors.
Despite these limitations, stateless sessions are very useful in high-performance batch processing situations where you need to work with real objects. When you can work with the raw data, there are usually even better alternatives, such as plain old SQL, HQL bulk actions, SqlBulkCopy, or ETL tools. For the plain old SQL route, simply access the ADO.NET connection object from session.Connection
and write your ADO.NET code as you normally would.
18.117.138.178