我正在尝试使用存储库模式,ninject用于流利的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 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();
}
}
}
在这里我设置了我的ninject东西。我做了一个流畅的方法。据我所知,这应该只发生一次每个Web请求(我认为它确实如此,因为这只在应用程序启动时调用)
我不确定我的GetSessionFactory方法是否应该是静态的。
然后我将IUsers接口绑定到UserRepo并传入构造函数参数。我猜我的Repos需要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()中有处理方法。
我的家庭控制器
private IUsers usersRepository;
public HomeController(IUsers usersRepository)
{
this.usersRepository = usersRepository;
}
public ActionResult Index()
{
Users test = new Users()
{
OpenIdIdentifier = "123",
Email = "as@hotmail.com",
};
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;
}
就像我说的那样,我很乐意摆脱这种方法,但我不确定如何让会话进入回购。所以,直到有人能告诉我,我想我现在必须这样做。
答案 0 :(得分:3)
首先,您可以考虑使用Ninject.Web.Mvc扩展,因为它已经有NinjectControllerFactory和NinjectHttpApplication为您连接控制器工厂。这也允许您在应用程序中创建IKernel,而不是在控制器工厂中。
第二,SessionFactory的创建成本非常高,所以它应该只在应用程序的生命周期内完成ONCE,即Singleton。
这是我在我的应用程序中使用的模块:
public class RepositoriesModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
// NHibernate
Bind<ISessionFactory>().ToProvider<SessionFactoryBuilder>()
.InSingletonScope();
Bind<ISession>()
.ToMethod( CreateSession )
.InRequestScope();
// Model Repositories
Bind( typeof( IRepository<> ) ).To( typeof( NHibernateRepository<> ) ).InScope( HttpOrThread );
Bind<IGameRepository>().To<GameRepository>();
Bind<ILogRepository>().To<LogRepository>();
Bind<IMemberRepository>().To<MemberRepository>();
Bind<IScopeManager>().To<ScopeManager>();
}
private ISession CreateSession( Ninject.Activation.IContext context )
{
var session = context.Kernel.Get<ISessionFactory>().OpenSession();
session.EnableFilter( DigitalLights.Model.FluentLogicalDeleteFilter.FilterName );
return session;
}
}
兴趣点 - ISessionFactory与Singleton范围内的Provider相关联。 Provider simple在启动时创建一次SessionFactory。这是提供商的样子。
/// <summary>
/// factory builder that uses FluentNHibernate to configure and return a SessionFactory
/// </summary>
public class SessionFactoryBuilder : Ninject.Activation.IProvider
{
private ISessionFactory _sessionFactory;
/// <summary>
/// constructor configures a SessionFactory based on the configuration passed in
/// </summary>
/// <param name="configuration"></param>
public SessionFactoryBuilder()
{
/// setup configuration here
var fluentConfig = Fluently.Configure()
.Database( MsSqlConfiguration.MsSql2005.ConnectionString( connectionString ) );
this._sessionFactory = fluentConfig.BuildSessionFactory();
}
#region IProvider Members
public object Create( Ninject.Activation.IContext context )
{
return _sessionFactory;
}
public Type Type
{
get { return typeof( ISessionFactory ); }
}
#endregion
}
接下来,NHibernate ISession由CreateSession方法创建,该方法从内核中检索ISessionFactory。 ISession的范围是请求。然后,存储库实现只是在它的构造函数中要求一个ISession。
另外,在我的应用程序中,在BeginRequest中启动了ITransaction,并在EndRequest中提交了ITransaction,以确保会话持久化并关闭。