NHibernate会议+;使用ASP.NET MVC 3的事务
目前我正在编写一个新的应用程序,尽管公司的标准是使用NHibernate(因为这是所有项目的标准),但由于ASP.NET MVC 3现在已经成熟,我正在使用它。我已经在控制器中实现了我的事务(这应该是您应该执行的方式),因此在我的根控制器中看起来是这样的:NHibernate会议+;使用ASP.NET MVC 3的事务,nhibernate,asp.net-mvc-3,Nhibernate,Asp.net Mvc 3,目前我正在编写一个新的应用程序,尽管公司的标准是使用NHibernate(因为这是所有项目的标准),但由于ASP.NET MVC 3现在已经成熟,我正在使用它。我已经在控制器中实现了我的事务(这应该是您应该执行的方式),因此在我的根控制器中看起来是这样的: [TransactionPerRequest] public class FbsController : Controller { } 然后,我的所有控制器都从此FbsController继承。之所以这样做,是因为我所有操作的90%都将转
[TransactionPerRequest]
public class FbsController : Controller
{
}
然后,我的所有控制器都从此FbsController
继承。之所以这样做,是因为我所有操作的90%都将转移到数据库中,因此创建事务并处理剩余10%操作(很少执行)的事务的开销不值得用[TransactionPerRequest]
来修饰每个操作
一直困扰我的是NHibernate课程。在repository类中,这与我所拥有的类似,尽管这在其他项目中有所不同:
public void Add(User user)
{
using (ISession session = NHibernateHelper.OpenSession())
{
session.Save(user);
}
}
public void Remove(User user)
{
using (ISession session = NHibernateHelper.OpenSession())
{
session.Delete(user);
}
}
public User GetById(int userId)
{
using (ISession session = NHibernateHelper.OpenSession())
{
return session.QueryOver<User>()
.Where(c => c.UserID == userId)
.SingleOrDefault();
}
}
公共作废添加(用户)
{
使用(ISession session=NHibernateHelper.OpenSession())
{
session.Save(用户);
}
}
公共无效删除(用户)
{
使用(ISession session=NHibernateHelper.OpenSession())
{
删除(用户);
}
}
公共用户GetById(int userId)
{
使用(ISession session=NHibernateHelper.OpenSession())
{
return session.QueryOver()
.Where(c=>c.UserID==UserID)
.SingleOrDefault();
}
}
因此,对于存储库中的大多数函数,我必须打开一个会话。有没有办法避免这种行为,这样我就不必在每个存储库方法中打开会话?这似乎有点违反直觉,因为我通常必须为每一个人这样做。我想知道其他人对事务和会话问题的解决方案是什么,我看到这些问题以各种方式散落在代码中
实际上,我希望我的存储库方法如下所示:
public void Add(User user)
{
session.Save(user);
}
public void Remove(User user)
{
session.Delete(user);
}
public User GetById(int userId)
{
return session.QueryOver<User>()
.Where(c => c.UserID == userId)
.SingleOrDefault();
}
公共作废添加(用户)
{
session.Save(用户);
}
公共无效删除(用户)
{
删除(用户);
}
公共用户GetById(int userId)
{
return session.QueryOver()
.Where(c=>c.UserID==UserID)
.SingleOrDefault();
}
所有事情都是隐式处理的。你可以看看Ayende Rahien的以下一系列博客文章:
我使用StructureMap在第一次调用ISession时自动启动会话,然后通过HttpRequest缓存会话。这使我可以在整个请求中使用延迟加载和事务,而无需太多编码麻烦 下面是我的引导程序的代码,它使用Fluent NHibernate和StructureMap为我设置了一切
public class Bootstrapper
{
public static ISessionFactory DBSessionFactory { get; set; }
public static ISession DBSession { get; set; }
public static void InitializeObjectFactory()
{
ObjectFactory.Initialize(x =>
{
x.PullConfigurationFromAppConfig = true;
x.Scan(y =>
{
y.Assembly(Assembly.GetAssembly(typeof(AccountController)));
y.Assembly(Assembly.GetAssembly(typeof(IMyProject)));
y.WithDefaultConventions();
}
);
// these are for NHibernate
x.ForRequestedType<ISessionFactory>()
.CacheBy(InstanceScope.Singleton)
.TheDefault.Is.ConstructedBy(GetDBSessionFactory);
// open session at beginning of every http request
// (the session is disposed at end of http request in global.asax's Application_EndRequest)
x.ForRequestedType<ISession>()
.CacheBy(InstanceScope.HttpContext)
.TheDefault.Is.ConstructedBy(GetDBSession);
});
}
public static ISessionFactory CreateSessionFactory()
{
return GetFluentConfiguration()
.BuildSessionFactory();
}
public static ISessionFactory GetDBSessionFactory()
{
if (DBSessionFactory == null)
{
DBSessionFactory = CreateSessionFactory();
}
return DBSessionFactory;
}
public static ISession GetDBSession()
{
if (DBSession == null)
{
DBSession = CreateSession();
}
return DBSession;
}
public static ISession CreateSession()
{
return GetDBSessionFactory()
.OpenSession();
}
public static FluentConfiguration GetFluentConfiguration()
{
string commandTimeout = ConfigurationManager.AppSettings["MyDBCommandTimeout"];
return Fluently.Configure()
.Database(// use your db configuration )
.Mappings(m =>
{
m.HbmMappings
.AddFromAssemblyOf<MyEO>();
m.FluentMappings
.AddFromAssemblyOf<MyEO>()
.AddFromAssemblyOf<MyEOMap>();
})
.ExposeConfiguration(
cfg =>
{
// command_timeout sets the timeout for the queries
cfg.SetProperty("command_timeout", commandTimeout);
}
);
}
}
关闭应用程序中的会话\u EndRequest():
现在你只要打电话
ObjectFactory.GetInstance<ISession>()
ObjectFactory.GetInstance()
从任何地方(我将其包装在一个helper类中以保持代码的简单性)和StructureMap都将为您提供缓存会话。我会按照以下思路做一些事情:
public class Repository<T> : IRepository<T>
{
private readonly ISessionFactory SessionFactory;
public Repository(ISessionFactory sessionFactory)
{
SessionFactory = sessionFactory;
}
public ISession Session
{
get
{
return SessionFactory.GetCurrentSession();
}
}
public T Get(long id)
{
return Session.Get<T>(id);
}
}
在my Global.asax.cs中:
public static ISessionFactory SessionFactory { get; set; }
然后在应用程序\u Start
中定义:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
var nhConfig = new Configuration().Configure();
SessionFactory = nhConfig.BuildSessionFactory();
}
然后创建该类:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class NHSession : ActionFilterAttribute
{
public NHSession()
{
Order = 100;
}
protected ISessionFactory sessionFactory
{
get
{
return MvcApplication.SessionFactory;
}
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var session = sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
session.BeginTransaction();
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
var session = CurrentSessionContext.Unbind(sessionFactory);
if (session != null)
{
if (session.Transaction.IsActive)
{
try
{
session.Transaction.Commit();
}
catch
{
session.Transaction.Rollback();
}
}
session.Close();
}
}
}
然后,我的通用存储库看起来大致如下:
public class Repository<T> : IRepository<T>
{
private readonly ISessionFactory SessionFactory;
public Repository(ISessionFactory sessionFactory)
{
SessionFactory = sessionFactory;
}
public ISession Session
{
get
{
return SessionFactory.GetCurrentSession();
}
}
public T Get(long id)
{
return Session.Get<T>(id);
}
}
这样我就能够在请求中使用工作单元。基本上,请求进入并启动会话,
SessionFactory
被传递到存储库的构造函数中。我在这里使用DI,但这是可选的。如果检测到错误,则在请求结束时提交会话(如果没有),则回滚会话。我建议您使用NHProf,因为它可以帮助您理解会话管理(如果设置不正确)。这没关系,但是如果您使用的是存储库模式,需要访问存储库中的会话,该怎么办?他没有提到这一点,会话仅在控制器中可用,因此使用QueryOver向DB发出的请求需要从控制器中完成。@Kezzer,您可以围绕HttpContext.Current.Items[“NHibernateSession”]编写一个包装类
然后配置DI框架,将其传递到存储库构造函数中。非常好的链接,这正是我想要的。非常感谢。
public class Repository<T> : IRepository<T>
{
private readonly ISessionFactory SessionFactory;
public Repository(ISessionFactory sessionFactory)
{
SessionFactory = sessionFactory;
}
public ISession Session
{
get
{
return SessionFactory.GetCurrentSession();
}
}
public T Get(long id)
{
return Session.Get<T>(id);
}
}
public class CmsContentRepository : Repository<CmsContent>, ICmsContentRepository
{
public CmsContentRepository(ISessionFactory sessionFactory) : base(sessionFactory) { }
}
[NHSession]
public ViewResult Revisions(int id)
{
var model = Service.CmsContentRepository.Get(id);
return View("Revisions", model);
}