I have quite a large data layer created in NHibernate for a new application/database I have been developing. It works well with the ASP .NET front-end, and there are no issues.
One of my requirements was to create a migration tool to move data from an old DB to this new system. I've done this by creating a windows application that uses my existing data layer (but without Context based sessions for each HTTP request). The migration tool will create about 100,000 rows all in all, spanning several tables/objects.
I create a session factory, and an individual session and a transaction for the entire procedure - wanting only to commit if the entire thing is successful. I've looked into the chapter about batch inserts for Hibernate (Java) and followed that for NHibernate:
_configuration.Properties[NHibernate.Cfg.Environment.BatchSize] = 256; _configuration.Properties[NHibernate.Cfg.Environment.UseSecondLevelCache] = "false";
I call ISession.Flush() and ISession.Clear() periodically to try and keep memory usage down, however this is of no avail. Whenever I save an object, the memory use increases, and easily uses GBs of RAM. If I attempt to commit and then close the session after every object is saved to the database, I still get a lot of memory use. Even if I close and re open the session factory every time a new object is added to the DB, the same problem occurs.
No matter what I do, I can't get the memory use down and it is making it impossible to run the application long enough for it to perform its task.
I haven't posted the code atm because it's quite large, but I can post specific portions if requested. The code for the "DataManager" is included. The SingleThread mode is used for this application.
Hibernate version: 1.2.1 GA
Name and version of the database you are using: SQL Server 2005
Code:
public enum DataManagerMode
{
MultipleThreadsWeb, // Will provide multiple sessions/transactions to the application, but only one per request
SingleThread // Will provide one session/transaction at a time to the entire application
}
/// <summary>
/// Manages access to the data/business entities.
/// </summary>
public class DataManager
{
// http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/
private const string _currentSessionKey = "nhibernate.current_session";
private const string _currentTransactionKey = "nhibernate.current_transaction";
private static ISessionFactory _sessionFactory;
private static Configuration _configuration;
private static DataManagerMode _mode = DataManagerMode.MultipleThreadsWeb;
public static DataManagerMode Mode
{
get { return _mode; }
set { _mode = value; }
}
private static ISession _singleThreadSession;
private static ITransaction _singleThreadTransaction;
static DataManager()
{
_configuration = new Configuration();
try
{
_configuration = _configuration.Configure();
}
catch (Exception)
{
// If it cannot configure from the config file, then try and populate the
// details. SetCustomConnectionString can be used after this.
_configuration.Properties[NHibernate.Cfg.Environment.Dialect] = "NHibernate.Dialect.MsSql2005Dialect";
_configuration.Properties[NHibernate.Cfg.Environment.ConnectionProvider] = "NHibernate.Connection.DriverConnectionProvider";
_configuration.Properties[NHibernate.Cfg.Environment.ConnectionDriver] = "NHibernate.Driver.SqlClientDriver";
_configuration.AddAssembly(Assembly.GetCallingAssembly());
}
}
/// <summary>
/// Sets a connection string that overrides that written in the configuration file.
/// Must be called before any other method otherwise an exception will occur.
/// </summary>
public static void SetConnectionString(string connectionString)
{
_configuration.Properties[NHibernate.Cfg.Environment.ConnectionString] = connectionString;
}
/// <summary>
/// Sets the DataManager to work in batch mode.
/// Must be called before any other method otherwise an exception will occur.
/// </summary>
public static void SetBatchMode(int size)
{
_configuration.Properties[NHibernate.Cfg.Environment.BatchSize] = size.ToString();
_configuration.Properties[NHibernate.Cfg.Environment.UseSecondLevelCache] = "false";
}
/// <summary>
/// (Internal) The current session
/// </summary>
private static ISession CurrentSession
{
get
{
if (Mode == DataManagerMode.SingleThread) //Added for single-thread mode
return _singleThreadSession;
if (CurrentContext.Items[_currentSessionKey] == null)
return null;
else
return (CurrentContext.Items[_currentSessionKey] as ISession);
}
set
{
if (Mode == DataManagerMode.SingleThread) //Added for single-thread mode
{
_singleThreadSession = value;
return;
}
if (value == null && CurrentContext.Items.Contains(_currentSessionKey))
CurrentContext.Items.Remove(_currentSessionKey);
else
CurrentContext.Items[_currentSessionKey] = value;
}
}
/// <summary>
/// (Internal) The current transaction
/// </summary>
private static ITransaction CurrentTransaction
{
get
{
if (Mode == DataManagerMode.SingleThread) //Added for single-thread mode
return _singleThreadTransaction;
if (CurrentContext.Items[_currentTransactionKey] == null)
return null;
else
return (CurrentContext.Items[_currentTransactionKey] as ITransaction);
}
set
{
if (Mode == DataManagerMode.SingleThread) //Added for single-thread mode
{
_singleThreadTransaction = value;
return;
}
if (value == null && CurrentContext.Items.Contains(_currentTransactionKey))
CurrentContext.Items.Remove(_currentTransactionKey);
else
CurrentContext.Items[_currentTransactionKey] = value;
}
}
/// <summary>
/// (Internal) The current context
/// </summary>
private static HttpContext CurrentContext
{
get
{
return HttpContext.Current;
}
}
/// <summary>
/// Retrieves the session factory
/// </summary>
public static ISessionFactory SessionFactory
{
get {
if (_sessionFactory == null)
_sessionFactory = _configuration.BuildSessionFactory();
return _sessionFactory;
}
}
/// <summary>
/// Retrieves the current session
/// </summary>
public static ISession Session
{
get
{
if (CurrentSession == null)
CurrentSession = SessionFactory.OpenSession();
return CurrentSession;
}
}
/// <summary>
/// Closes the current session
/// </summary>
public static void CloseSession()
{
if (CurrentSession == null)
return;
CurrentSession.Close();
CurrentSession = null;
}
/// <summary>
/// Closes the session factory
/// </summary>
public static void CloseSessionFactory()
{
if (_sessionFactory != null)
{
_sessionFactory.Close();
_sessionFactory = null;
}
}
/// <summary>
/// Begins a transaction
/// </summary>
public static void BeginTransaction()
{
if (CurrentTransaction == null)
CurrentTransaction = Session.BeginTransaction();
}
/// <summary>
/// Commits a transaction
/// </summary>
public static void CommitTransaction()
{
try
{
if (CurrentTransaction != null && !CurrentTransaction.WasCommitted
&& !CurrentTransaction.WasRolledBack)
{
CurrentTransaction.Commit();
CurrentTransaction = null;
}
}
catch (HibernateException ex)
{
RollbackTransaction();
throw ex;
}
}
/// <summary>
/// Rolls back a transaction
/// </summary>
public static void RollbackTransaction()
{
try
{
if (CurrentTransaction != null && !CurrentTransaction.WasCommitted
&& !CurrentTransaction.WasRolledBack)
{
CurrentTransaction.Rollback();
CurrentTransaction = null;
}
}
catch (HibernateException ex)
{
throw ex;
}
}
}
[/code]