应用程序设计:NH会话管理、通用存储库、ASP.NET MVC
本文关键字:存储 ASP NET MVC NH 会话 管理 应用 程序设计 | 更新日期: 2023-09-27 18:21:11
定义了domain model
之后,我想弄清楚如何完成其余的工作。
数据访问层
我以前读过,没有必要在ISession
上编写自己的UnitOfWork
实现(尽管我发现了很多关于如何很好地完成它的信息)。所以我很困惑。。我有这样的存储库界面:
public interface IRepository<T> where T: AbstractEntity<T>, IAggregateRoot
{
T Get(Guid id);
IQueryable<T> Get(Expression<Func<T, Boolean>> predicate);
IQueryable<T> Get();
T Load(Guid id);
void Add(T entity);
void Remove(T entity);
void Remove(Guid id);
void Update(T entity);
void Update(Guid id);
}
在具体实施中有两种选择:
选项A
是通过构造函数注入ISessionFactory
,并具有类似于的内容
public class Repository<T> : IRepository<T> where T : AbstractEntity<T>, IAggregateRoot
{
private ISessionFactory sessionFactory;
public Repository(ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
public T Get(Guid id)
{
using(var session = sessionFactory.OpenSession())
{
return session.Get<T>(id);
}
}
}
选项B
是使用NHibernateHelper
类
using(var session = NHibernateHelper.GetCurrentSession())
{
return session.Get<T>(id);
}
其中NHibernateHelper
为
internal sealed class NHibernateHelper
{
private const string CurrentSessionKey = "nhibernate.current_session";
private static readonly ISessionFactory sessionFactory;
static NHibernateHelper()
{
sessionFactory = new Configuration().Configure().BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if(currentSession == null)
{
currentSession = sessionFactory.OpenSession();
context.Items[CurrentSessionKey] = currentSession;
}
return currentSession;
}
public static void CloseSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if(currentSession == null)
{
return;
}
currentSession.Close();
context.Items.Remove(CurrentSessionKey);
}
public static void CloseSessionFactory()
{
if(sessionFactory != null)
{
sessionFactory.Close();
}
}
}
首选哪个选项?
为什么(除了注射)?
如果我使用选项A
,我将把ISessionFactory
的配置放在哪里?
它应该放在ASP.NET MVC
项目的某个地方吗?怎样
感谢您阅读这个怪物问题!感谢您的指导!
如何使用mvc处理注入依赖关系在某种程度上是特定于版本的,但总是有助于使用真正的依赖注入(DI)容器。无论您对其进行何种分割,此解决方案都需要将ISession注入存储库,而不是ISessionFactory。这允许DI容器正确地管理会话的生存期。
假设您使用的是Asp.NetMVC3,并且还没有连接到特定DI容器,那么启动Nuget控制台并键入:
install-package Ninject.MVC3
这将下载Ninject(这是一个DI容器)并配置你的mvc应用程序来使用它。它还将创建一个文件~/App_Start/NinjectMVC3.cs,在那里你可以配置你的依赖关系。
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISessionFactory>()
.ToMethod(c => new Configuration().Configure().BuildSessionFactory())
.InSingletonScope();
kernel.Bind<ISession>()
.ToMethod((ctx) => ctx.Kernel.Get<ISessionFactory>().OpenSession())
.InRequestScope();
kernel.Bind<IRepository<>>().To<Repository<>>();
}
第一条语句告诉ninject,当某个东西需要ISessionFactory时,它应该延迟初始化NHibernate并创建一个。然后,在应用程序的整个生命周期内,这个会话工厂将作为应用程序范围内的单例进行保存。
第二条语句告诉ninject,当某个东西需要ISession时,它应该获取ISessionFactory的实例并调用OpenSession()。然后,该会话在请求的范围内被重用,并在请求结束时被销毁。
第三条语句告诉ninject,当某个东西需要任何类型的IRepository时,它应该使用内置的逻辑来解决依赖关系。
从这里,您可以按照如下方式编写代码,一切都应该正常工作。
public class WidgetController : Controller
{
private readonly IRepository<Widget> _repository;
public WidgetController(IRepository<Widget> repository)
{
_repository = repository;
}
}
关于存储库,我想向您介绍一篇出色的博客文章。存储库是新的Singleton
我通常在我的存储库上使用只读属性,比如这个
protected ISession Session
{
get
{
return NHibernateSessionFactory.CurrentFor(dataBaseFactoryKey);
}
}
我的NHibernateSessionFactory是这样工作的。
在web应用程序中,每个web请求都应该使用模式NH会话。我认为每个web请求应该只有一个会话,并且您的存储库应该使用这个会话。要实现这一点,您需要编写IHttpModule,它将在请求开始时打开会话、开始事务并将会话绑定为环境(当前)会话,在请求结束时结束事务并关闭会话。您还需要将current_session_text_class设置为"web"。然后您的Repository/DAO将看起来像这个
public TEntity Get(object id)
{
return sessionFactory.GetCurrentSession().Get<TEntity>(id);
}
MVC和NHibernate的最佳模式是每个请求的会话
步骤:
- 在Global.asax中添加public static ISessionFactorySessionFactory
-
在Application_Start()中配置和构建会话工厂:
var config=新配置().Configure()
SessionFactory=配置。BuildSessionFactory(); -
在Application_BeginRequest中打开会话并将其绑定到CurrentSessionContext:
var nhSession=SessionFactory.OpenSession()
CurrentSessionContext.Bind(会话); -
在Application_EndRequest()中解除绑定并处理会话
现在,在您的控制器中,您可以访问您的会话调用:
Global.SessionFactory.GetCurrentSession();
编辑:关注@hival评论
在控制器内部,使用块处理模型,并根据逻辑执行提交/回滚。