In order to create loose coupling architecture on my web applications, I have created my own implementation for ORM, in this case, NHibernate.
I want you please to review the code and tell me if you think it can work in a real world on high traffic app.
I have divided the API to transaction and session. There are some cases where I want to use session with out transaction, and there are times when I need multiple transaction in a single HTTP request.
This is the session API:
public interface IDalSession : IDisposable
{
IDalSession Start();
IDalTransaction StartWithTransaction();
bool IsActive();
T Save<T>(T entity);
IQueryOver<T> QueryOver<T>() where T : class;
IQueryable<T> Query<T>() where T : class;
T CreateQuery<T>(string query) where T : class;
void ExecuteUpdate(string sqlQuery);
}
This is the transaction API:
public interface IDalTransaction : IDisposable
{
bool IsActive { get; }
void MarkForRollBack();
void Commit();
T Save<T>(T entity);
IQueryOver<T> QueryOver<T>() where T : class;
IQueryable<T> Query<T>() where T : class;
T CreateQuery<T>(string query) where T : class;
void ExecuteUpdate(string sqlQuery);
}
This is the session factory (the session suppose to exist per HTTP request): I am aware that I am coupled with the MySQL call below; it will be removed.
public class NHibernateSessionFactory
{
public static ISessionFactory SessionFactory;
public static void Configure(DatabaseConnectionProperties database)
{
if (SessionFactory == null)
{
FluentConfiguration configuration;
configuration = Fluently.Configure().Database(
MySQLConfiguration.Standard.ConnectionString(
mysql =>
mysql.Database(database.DatabaseName).Username(database.UserName).Password(database.Password).
Server(database.Host)
));
foreach (Type entity in database.Entities)
{
configuration.Mappings(m => m.FluentMappings.AddFromAssembly(entity.Assembly)
.Conventions.Add(new LowerCaseWithUnderConvention())
);
}
if (database.GenerateTables)
{
configuration.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true, true));
}
else
{
configuration.ExposeConfiguration(cfg => new SchemaExport(cfg));
}
configuration.ExposeConfiguration(
c => c.SetProperty("current_session_context_class", "web"));
SessionFactory = configuration.BuildSessionFactory();
}
}
public static ISession GetCurrentSession()
{
if (!CurrentSessionContext.HasBind(SessionFactory))
{
CurrentSessionContext.Bind(SessionFactory.OpenSession());
}
return SessionFactory.GetCurrentSession();
}
public static IDalSession OpenSession()
{
return new DalSession(SessionFactory);
}
public static void CloseSession()
{
SessionFactory.Close();
}
}
This is how I inject the session per request:
kernel.Bind<IDalSession>()
.ToProvider<HttpDalSessionProvider>()
.InRequestScope();
This is how I provide it to Ninject:
public class HttpDalSessionProvider : Provider<IDalSession>
{
private static DatabaseConnectionProperties GetDatabaseConnectionProperties()
{
List<Type> entities = new List<Type> {typeof (BillingInfo)};
return new DatabaseConnectionProperties(
ConfigurationManager.AppSettings["DbHost"],
ConfigurationManager.AppSettings["DbName"],
ConfigurationManager.AppSettings["DbUser"],
ConfigurationManager.AppSettings["DbPassword"],
entities,true
);
}
protected override IDalSession CreateInstance(IContext context)
{
NHibernateSessionFactory.Configure(GetDatabaseConnectionProperties());
return NHibernateSessionFactory.OpenSession().Start();
}
}