Created
May 7, 2009 22:18
-
-
Save tobinharris/108433 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using FluentNHibernate; | |
using FluentNHibernate.AutoMap; | |
using FluentNHibernate.Cfg.Db; | |
using NHibernate; | |
using NHibernate.Cfg; | |
using NHibernate.Context; | |
using NHibernate.Event; | |
using Portal.Core.Application.DataAccess; | |
namespace Portal.Core.Infrastructure.DataAccess | |
{ | |
/// <summary> | |
/// Simple NHibernate Unit Of Work class that will work in ASP.NET and Unit Tests. | |
/// | |
/// Usage: | |
/// | |
/// GLOBAL.ASCX.CS | |
/// | |
/// void Application_Start(object sender, EventArgs e) | |
/// { | |
/// UoW.Configure("server=local;catalog=test;"); | |
/// } | |
/// | |
/// void Application_BeginRequest(object sender, EventArgs e) | |
/// { | |
/// UoW.Start(); | |
/// } | |
/// | |
/// void Application_EndRequest(object sender, EventArgs e) | |
/// { | |
/// if(UoW.IsStarted) | |
/// UoW.End(); | |
/// } | |
/// | |
/// </summary> | |
public static class UoW | |
{ | |
#region Environment enum | |
/// <summary> | |
/// What environment do we want to run? Web or Other (suitable for unit tests, desktop clients or remoting) | |
/// </summary> | |
public enum Environment | |
{ | |
Web, | |
Other, | |
Test | |
} | |
#endregion | |
/// <summary> | |
/// NHibernate session factory is expensive to create. | |
/// Therefore we keep it as a static variable so we only create it once. | |
/// It's thread safe, so static if fine for both web and desktop. | |
/// </summary> | |
private static ISessionFactory _nhibernateSessionFactory; | |
/// <summary> | |
/// We stash the configuration here just to be helpful, in case the app needs it. | |
/// This is optional really. | |
/// </summary> | |
public static Configuration NHibernateConfiguration { get; private set; } | |
/// <summary> | |
/// Get the session. You must Start the Unit of Work before calling this. | |
/// </summary> | |
public static ISession Session | |
{ | |
get { return _nhibernateSessionFactory.GetCurrentSession(); } | |
} | |
public static bool IsStarted | |
{ | |
get | |
{ | |
if (_nhibernateSessionFactory == null) return false; | |
return CurrentSessionContext.HasBind(_nhibernateSessionFactory); | |
} | |
} | |
/// <summary> | |
/// Get the session factory. Can be accessed once has be created. | |
/// </summary> | |
public static ISessionFactory SessionFactory | |
{ | |
get { return _nhibernateSessionFactory; } | |
} | |
/// <summary> | |
/// Constructor. We'd only create One UoW class for the entire application (one per ASP.NET App Pool) | |
/// </summary> | |
/// <param name="nhibernateConfiguration"></param> | |
public static void Configure(Configuration nhibernateConfiguration) | |
{ | |
NHibernateConfiguration = nhibernateConfiguration; | |
_nhibernateSessionFactory = nhibernateConfiguration.BuildSessionFactory(); | |
} | |
public static Configuration Configure(string connectionString, Environment env) | |
{ | |
return Configure(connectionString, env, x => {}); | |
} | |
/// <summary> | |
/// Simpler constructor. We'd only create One UoW class for the entire application (one per ASP.NET App Pool) | |
/// </summary> | |
/// <param name="connectionString"></param> | |
/// <param name="env">Where will this UoW be used? Web? </param> | |
public static Configuration Configure(string connectionString, Environment env, Action<Configuration> configurationAction) | |
{ | |
NHibernateConfiguration = new Configuration(); | |
//we will poke some additional properties into the config | |
var additionalProperties = new Dictionary<string, string>(); | |
//the first is the session context. This allows NHibernate to take care of where it's being used. | |
//See NHibernate in Action page 327 | |
if (env == Environment.Web) | |
{ | |
additionalProperties.Add("current_session_context_class", typeof (WebSessionContext).FullName); | |
} | |
else | |
additionalProperties.Add("current_session_context_class", typeof(CallSessionContext).FullName); | |
additionalProperties.Add("use_proxy_validator", "false"); | |
//additionalProperties.Add("query.substitutions", "true 1, false 0, True 1, False 0, yes 'Y', no 'N', bw_or ^, bw_and &, bw_not ~"); | |
AutoPersistenceModel mappings = MyMappings.Create(); | |
if (env == Environment.Test && string.IsNullOrEmpty(connectionString)) | |
{ | |
SQLiteConfiguration | |
.Standard | |
.InMemory() | |
.QuerySubstitutions("true 1, false 0, True 1, False 0, yes 'Y', no 'N', bw_or ^, bw_and &, bw_not ~") | |
//.UsingFile("test.db") | |
.ShowSql() | |
.ConfigureProperties(NHibernateConfiguration) | |
.AddProperties(additionalProperties) | |
.AddAutoMappings(mappings) | |
//.SetListener(ListenerType.FlushEntity, new CustomSaveEventListener()) | |
; | |
// if(Directory.Exists("c:\\Mappings")) | |
// mappings.WriteMappingsTo("c:\\Mappings\\"); | |
// else | |
// Console.Write("Not dumping mappings to file for preview because no c:\\Mappings folder."); | |
} | |
else | |
{ | |
//use Fluent to fluently configure the database | |
//you'd have to change this if using MySQL for example. | |
MsSqlConfiguration | |
.MsSql2005 | |
.ConnectionString(c => c.Is(connectionString)) | |
.QuerySubstitutions("true 1, false 0, True 1, False 0, yes 'Y', no 'N', bw_or ^, bw_and &, bw_not ~") | |
.ShowSql() | |
.ConfigureProperties(NHibernateConfiguration) | |
.AddProperties(additionalProperties) | |
.AddAutoMappings(mappings) | |
.SetProperty("generate_statistics", "true") | |
.SetListener(ListenerType.FlushEntity, new CustomSaveEventListener()) | |
; | |
} | |
NHibernateConfiguration.SetListener(ListenerType.Update, new CustomUpdateEventListener()); | |
NHibernateConfiguration.SetListener(ListenerType.SaveUpdate, new CustomSaveOrUpdateEventListener()); | |
configurationAction.Invoke(NHibernateConfiguration); | |
//set the static session factory (that will live for as long as the AppPool does | |
_nhibernateSessionFactory = NHibernateConfiguration.BuildSessionFactory(); | |
return NHibernateConfiguration; | |
} | |
/// <summary> | |
/// Start a new unit of work. | |
/// </summary> | |
public static void Start() | |
{ | |
if(_nhibernateSessionFactory == null) return; | |
//stash a new session where we can get at it at any time. NHibernate already | |
//has a CurrentSessionContext class for keeping sessions somewhere accessible. | |
CurrentSessionContext.Bind(_nhibernateSessionFactory.OpenSession()); | |
//We don't want to push any work to the DB unless we explicitly call Commit. | |
Session.FlushMode = FlushMode.Commit; | |
//all our work should be in a transaction | |
Session.BeginTransaction(); | |
} | |
/// <summary> | |
/// Send all work done in the UoW's transaction to the database. Also starts a new transaction | |
/// ready for any additional work you do. | |
/// You can call this method multiple times for during a single Unit of Work | |
/// if you want to send several updates separately. | |
/// </summary> | |
public static void Commit() | |
{ | |
Session.Transaction.Commit(); | |
Session.BeginTransaction(); | |
} | |
/// <summary> | |
/// End the current unit of work. | |
/// </summary> | |
public static void End() | |
{ | |
//We want to roll back any active transaction. If the user of this class wanted to commit | |
//any updates then he should have to have called UoW.Commit(). | |
if (Session.Transaction != null && Session.Transaction.IsActive) Session.Transaction.Rollback(); | |
//close the session | |
Session.Close(); | |
//Session is disposable, and therefor it's good to call Dispose() once we're done with it. | |
Session.Dispose(); | |
//unbind the session from the context as we won't be needing it. | |
CurrentSessionContext.Unbind(_nhibernateSessionFactory); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment