如何使用 Fluent nhibernate 设置我的存储库?
我正在尝试使用存储库模式,ninject for DI with Fluent nhibernate。
我把我的解决方案分成了 3 个项目,
web ui - controllers,view (I am using asp.net mvc 2.0)
framework - repository, domain, fluent mapping
tests - where my unit tests will go.
所以我已经设置好了。
Global.aspx
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
}
所以我在我的应用程序中开始使用 ninject 控制器工厂。
NinjectControllerFactory
public class NinjectControllerFactory : DefaultControllerFactory
{
// A Ninject "kernel" is the thing that can supply object instances
private IKernel kernel = new StandardKernel(new T4GDemoSevice());
// ASP.NET MVC calls this to get the controller for each request
protected override IController GetControllerInstance(RequestContext context, Type controllerType)
{
if (controllerType == null)
return null;
return (IController)kernel.Get(controllerType);
}
// Configures how abstract service types are mapped to concrete implementations
private class DemoSevice : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToMethod(c => GetSessionFactory()).InSingletonScope();
Bind<ISession>().ToMethod(c => c.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
Bind<IUsers>().To<UsersRepo>().WithConstructorArgument("session",GetSessionFactory());
}
public static ISessionFactory GetSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<T4G_Demo.Framework.Data.NhibernateMapping.UserMap>())
.BuildSessionFactory();
}
}
}
在这里我设置了我的 ninject 东西。我做了一个设置流畅的方法。据我了解,每个网络请求这只应该发生一次(我认为它会发生,因为这只在应用程序启动时被调用),
但我不确定我的 GetSessionFactory 方法是否应该是静态的。
然后,我将 IUsers 接口绑定到 UserRepo 并传入构造函数参数。我猜测我的存储库需要 nhibernate 会话来执行某些操作。所以我不确定如何将它传递到我的存储库。
我认为我所拥有的可能是错误的,因为每个存储库都会得到它的配置?
存储库
public class UsersRepo : IUsers
{
private ISessionFactory session;
public UsersRepo(ISessionFactory session)
{
this.session = session;
}
public void CreateUser(Domain.Users newUser)
{
var openSession = session.OpenSession();
var transaction = openSession.BeginTransaction();
openSession.SaveOrUpdate(newUser);
transaction.Commit();
}
}
我尝试创建一个存储库,但我再次不确定如何使用会话来完成它。就像我必须打开它并开始交易一样。我不确定这是否应该在其他地方完成。
我也不确定在经过这些方法后是否应该处置它。我看到人们在 application_end() 中有 dispose 方法。
我的家庭控制器
private IUsers usersRepository;
public HomeController(IUsers usersRepository)
{
this.usersRepository = usersRepository;
}
public ActionResult Index()
{
Users test = new Users()
{
OpenIdIdentifier = "123",
Email = "[email protected]",
};
usersRepository.CreateUser(test);
return View();
}
最后,我刚刚制作了一个虚拟控制器,它创建一个虚拟用户并将其插入数据库。它有效,但就像我说的,会话部分让我感到困惑,因为我不知道如何传递它。
编辑
这是我到目前为止所想出的。它仍然不是我想要的(我宁愿每个请求都有一个会话),但它似乎正在工作。
Ninject 工厂
public static ISessionFactory GetSessionFactory()
{
if (session == null)
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<T4G_Demo.Framework.Data.NhibernateMapping.UserMap>())
//.ExposeConfiguration(BuidSchema)
.BuildSessionFactory();
}
return session;
}
我添加了一个 if 语句来检查会话是否已启动。所以这样应该可以解决每次启动SessionFactory的问题。
我的存储库看起来像这样
public class UsersRepo : IUsers
{
private ISession openSession;
private ISessionFactory session;
public UsersRepo(ISessionFactory session)
{
this.openSession = session.OpenSession();
this.session = session;
}
public void CreateUser(Users newUser)
{
openSession = NhibernateUtilities.OpenIfClosed(session, openSession);
openSession.SaveOrUpdate(newUser);
}
public Users GetUser(Guid userId)
{
openSession = NhibernateUtilities.OpenIfClosed(session, openSession);
var query = from b in openSession.Query<Users>()
where b.UserId == userId
select b;
return query.SingleOrDefault();
}
public void DeleteUser(Users user)
{
openSession = NhibernateUtilities.OpenIfClosed(session, openSession);
openSession.Delete(user);
}
public void SaveOrUpdate()
{
using (openSession)
{
using (var transaction = openSession.BeginTransaction())
{
transaction.Commit();
}
}
}
因此,在每种方法中,我都会检查会话是否打开,如果没有,则通过此方法打开一个会话。
public static ISession OpenIfClosed(ISessionFactory session, ISession openSession)
{
if (openSession.IsOpen == false)
{
return session.OpenSession();
}
return openSession;
}
就像我说的,我很想摆脱这种方法,但我不确定如何将会话转移到存储库。因此,在有人可以向我展示之前,我想我现在必须这样做。
I am trying to use the repository pattern, ninject for DI with fluent nhibernate.
I broken up my solution into 3 projects
web ui - controllers,view (I am using asp.net mvc 2.0)
framework - repository, domain, fluent mapping
tests - where my unit tests will go.
So I have setup this up.
Global.aspx
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
}
So I put in my application start to use ninject controller factory.
NinjectControllerFactory
public class NinjectControllerFactory : DefaultControllerFactory
{
// A Ninject "kernel" is the thing that can supply object instances
private IKernel kernel = new StandardKernel(new T4GDemoSevice());
// ASP.NET MVC calls this to get the controller for each request
protected override IController GetControllerInstance(RequestContext context, Type controllerType)
{
if (controllerType == null)
return null;
return (IController)kernel.Get(controllerType);
}
// Configures how abstract service types are mapped to concrete implementations
private class DemoSevice : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToMethod(c => GetSessionFactory()).InSingletonScope();
Bind<ISession>().ToMethod(c => c.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
Bind<IUsers>().To<UsersRepo>().WithConstructorArgument("session",GetSessionFactory());
}
public static ISessionFactory GetSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<T4G_Demo.Framework.Data.NhibernateMapping.UserMap>())
.BuildSessionFactory();
}
}
}
Here I setup my ninject stuff. I made a method that sets up fluent. As I understand it this should only happen once per web request(which I think it does since this only gets call in the application start)
I am not sure though if my GetSessionFactory method should be static.
I then bind my IUsers interface to my UserRepo and and pass in a constructor argument. I am guessing that my Repos need the session of nhibernate to do something. So I was not sure how to pass it to my repos.
I think what I have might be wrong as each repository would get it's on configuration??
Repository
public class UsersRepo : IUsers
{
private ISessionFactory session;
public UsersRepo(ISessionFactory session)
{
this.session = session;
}
public void CreateUser(Domain.Users newUser)
{
var openSession = session.OpenSession();
var transaction = openSession.BeginTransaction();
openSession.SaveOrUpdate(newUser);
transaction.Commit();
}
}
I tried to make a repository but again I am not sure how to do it with the session. Like I have to open it up and begin the transaction. I am not sure if that should be done somewhere else.
I was also not sure if I should dispose it after it goes through the methods. I seen people have dispose methods in the application_end().
My Home Controller
private IUsers usersRepository;
public HomeController(IUsers usersRepository)
{
this.usersRepository = usersRepository;
}
public ActionResult Index()
{
Users test = new Users()
{
OpenIdIdentifier = "123",
Email = "[email protected]",
};
usersRepository.CreateUser(test);
return View();
}
Finally I just made a dummy controller that creates a dummy user and inserts it into the db. It works but like I said the session part confuses me as I am not sure how to pass it along.
Edit
This is what I have come up with so far. It still not what I want(I rather have a session per request) but it seems to be working.
Ninject factory
public static ISessionFactory GetSessionFactory()
{
if (session == null)
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<T4G_Demo.Framework.Data.NhibernateMapping.UserMap>())
//.ExposeConfiguration(BuidSchema)
.BuildSessionFactory();
}
return session;
}
I added a if statement to check if the session is started or not. So this should take care of the problem of starting SessionFactory each time.
My repo looks like this
public class UsersRepo : IUsers
{
private ISession openSession;
private ISessionFactory session;
public UsersRepo(ISessionFactory session)
{
this.openSession = session.OpenSession();
this.session = session;
}
public void CreateUser(Users newUser)
{
openSession = NhibernateUtilities.OpenIfClosed(session, openSession);
openSession.SaveOrUpdate(newUser);
}
public Users GetUser(Guid userId)
{
openSession = NhibernateUtilities.OpenIfClosed(session, openSession);
var query = from b in openSession.Query<Users>()
where b.UserId == userId
select b;
return query.SingleOrDefault();
}
public void DeleteUser(Users user)
{
openSession = NhibernateUtilities.OpenIfClosed(session, openSession);
openSession.Delete(user);
}
public void SaveOrUpdate()
{
using (openSession)
{
using (var transaction = openSession.BeginTransaction())
{
transaction.Commit();
}
}
}
So in each method I check if a session is open if not then I open one through this method.
public static ISession OpenIfClosed(ISessionFactory session, ISession openSession)
{
if (openSession.IsOpen == false)
{
return session.OpenSession();
}
return openSession;
}
Like I said I would love to get rid of this method but I am unsure how to get the session then over to the repos. So until someone can show me I guess I have to do it like this for now.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,您可能会考虑使用 Ninject.Web.Mvc 扩展,因为它已经具有 NinjectControllerFactory 和一个为您连接控制器工厂的 NinjectHttpApplication 。这还允许您在应用程序中创建 IKernel,这是它应该在的位置,而不是在控制器工厂中。
其次,SessionFactory 的创建成本非常高,因此在应用程序的生命周期内只应执行一次,即单例。
这是我在应用程序中使用的模块:
兴趣点 - ISessionFactory 与 Singleton 范围内的 Provider 绑定。 Provider 在启动时简单地创建 SessionFactory。这是提供者的样子。
接下来,NHibernate ISession 通过 CreateSession 方法创建,该方法从内核检索 ISessionFactory。 ISession 的范围仅限于请求。然后,存储库实现只需在其构造函数中请求 ISession 即可。
另外,在我的应用程序中,在 BeginRequest 中启动 ITransaction,在 EndRequest 中提交 ITransaction,以确保会话保持并关闭。
first, you might consider using the Ninject.Web.Mvc extension, since it already has the NinjectControllerFactory and a NinjectHttpApplication that wires up the controller factory for you. this also allows you to create the IKernel in your application, which is where it should be, not in your controller factory.
second, the SessionFactory is very expensive to create, so it should only be done ONCE for the lifetime of the application, i.e., a Singleton.
here is the module I'm using in my applications:
points of interest - the ISessionFactory is tied to a Provider in Singleton scope. the Provider simple creates the SessionFactory once on startup. here's what the Provider looks like.
next, the NHibernate ISession is create by the method CreateSession which retrieves the ISessionFactory from the Kernel. the ISession is scoped to the request. then, the repository implementation simply asks for an ISession in it's constructor.
also, in my app, in BeginRequest a ITransaction is started, and in EndRequest the ITransaction is committed, to make sure the session is persisted and closed.