Using stateless sessions

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.

In this recipe, we'll use a stateless session to update our movie prices.

Getting ready

Just as before, follow Configuring NHibernate with App.config from Chapter 2 to set up a console application with NHibernate and our Eg.Core model.

How to do it...

  1. To create some data with which to work, add the following code to your Main method:
    using (var session = sessionFactory.OpenStatelessSession())
    {
      using (var tx = session.BeginTransaction())
      {
        for (int i = 0; i < 1000; i++)
        session.Insert(new Movie()
        {
          Name = "Movie " + i.ToString(),
          Description = "A great movie!",
          UnitPrice = 14.95M,
          Director = "Johnny Smith"
        });
        tx.Commit();
      }
    }
  2. Next, let's update our movie prices. Add the following code to the Main method:
    using (var session = sessionFactory.OpenStatelessSession())
    {
      using (var tx = session.BeginTransaction())
      {
      var movies = GetMovies(session);
      foreach (var movie in movies)
      {
        UpdateMoviePrice(movie);
        session.Update(movie);
      }
      tx.Commit();
      }
    }
  3. Add the GetMovies method:
    static IEnumerable<Movie> GetMovies(IStatelessSession session)
    {
      return session.CreateQuery("from Movie")
      .List<Movie>();
    }
  4. Finally, add our 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;
    }

How it works...

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, because we have batching turned on, they don't happen immediately either. 100 insert statements are queued up at a time and sent all together. If we turned batching 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 a query. These movies are detached; they are not associated with a session. Entities can't be associated with stateless sessions. This is the case whether we load our entities with a query or the Get method.

Because stateless sessions don't implement automatic dirty checking, we have to call session.Update to save our changes to each movie.

There's more...

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. You must explicitly insert, update, or delete each entity one at a time. Stateless sessions also bypass the second-level cache, event listeners, interceptors, and even the NHibernate.SQL log4net logger.

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 better alternatives like plain old SQL, HQL bulk actions, SqlBulkCopy, or ETL tools. For the plain old SQL route, simple access the ADO.NET connection object from session.Connection and write your ADO.NET code as you normally would.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.71.94