0

Ich versuche, das Repository-Muster, Ninject für DI mit flüssigem Nhibernate zu verwenden.Wie richte ich mein Repository mit flüssigem Nhibernate ein?

ich meine Lösung in drei Projekte aufgeteilt

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 habe ich Setup diese auf.

Global.aspx

protected void Application_Start() 
     { 
      AreaRegistration.RegisterAllAreas(); 

      RegisterRoutes(RouteTable.Routes); 

      ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()); 
     } 

Also habe ich in meiner Anwendung Start ninject Controller Factory zu verwenden.

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(); 
      } 

     } 
    } 

Hier habe ich mein Setup ninject Sachen. Ich habe eine Methode entwickelt, die fließend funktioniert. Wie ich es verstehe, sollte dies nur einmal pro Web-Anfrage geschehen (was ich denke, da dies nur beim Start der Anwendung ruft)

Ich bin mir nicht sicher, ob meine GetSessionFactory-Methode sollte statisch sein.

Ich binde dann meine IUsers-Schnittstelle zu meinem UserRepo und übergeben ein Konstruktorargument. Ich vermute, dass meine Repos die Sitzung von Nhibernate brauchen, um etwas zu tun. Also war ich mir nicht sicher, wie ich es an meine Repos weitergeben sollte.

Ich denke, was ich habe könnte falsch sein, wie jedes Repository würde es auf Konfiguration bekommen?

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(); 
     } 
    } 

Ich habe versucht, ein Repository zu machen, aber wieder bin ich nicht sicher, wie es mit der Sitzung zu tun. Ich muss es öffnen und die Transaktion beginnen. Ich bin mir nicht sicher, ob das woanders gemacht werden sollte.

Ich war auch nicht sicher, ob ich es entsorgen sollte, nachdem es die Methoden durchläuft. Ich habe gesehen, dass Leute Methoden im application_end() entsorgen.

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(); 
     } 

Schließlich habe ich nur ein Dummy-Controller, einen Dummy-Benutzer erstellt und fügt es in der db. Es funktioniert, aber wie ich schon sagte, der Sitzungsteil verwirrt mich, da ich nicht sicher bin, wie ich es weitergeben soll.

bearbeiten

Dies ist, was ich mit so weit gekommen sind. Es ist immer noch nicht das, was ich will (ich habe eher eine Sitzung pro Anfrage), aber es scheint zu funktionieren.

Ninject Fabrik

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;    
     } 

Ich habe eine if-Anweisung zu prüfen, ob die Sitzung gestartet wird oder nicht. Dies sollte also das Problem beheben, dass jedes Mal SessionFactory gestartet wird.

Mein Repo sieht wie folgt aus

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 jeder Methode, die ich überprüfen, ob eine Sitzung geöffnet ist, wenn nicht, dann ich eine durch diese Methode öffnen.

public static ISession OpenIfClosed(ISessionFactory session, ISession openSession) 
     { 
      if (openSession.IsOpen == false) 
      { 
       return session.OpenSession(); 
      } 

      return openSession; 
     } 

Wie gesagt würde ich diese Methode zu erhalten Liebe zu befreien, aber ich bin nicht sicher, wie die Sitzung zu dem repos dann über zu bekommen. Also, bis mir jemand zeigen kann, muss ich es jetzt wohl so machen.

Antwort

3

Zuerst sollten Sie die Erweiterung Ninject.Web.Mvc in Erwägung ziehen, da sie bereits über die NinjectControllerFactory und eine NinjectHttpApplication verfügt, die die Controller Factory für Sie verdrahten. Dies ermöglicht Ihnen auch, den IKernel in Ihrer Anwendung zu erstellen, und zwar dort, wo er sein sollte, und nicht in Ihrer Controller Factory. Zweitens ist die Erstellung der SessionFactory sehr teuer, weshalb sie nur EINMAL für die Lebensdauer der Anwendung, d. H. Ein Singleton, durchgeführt werden sollte.

hier ist das Modul ich in meinen Anwendungen bin:

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; 
    } 

} 

Sehenswürdigkeiten - die ISessionFactory an einen Provider in Singleton Umfang gebunden ist. Der Provider erstellt die SessionFactory einmalig beim Start. So sieht der Provider aus.

/// <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 
} 

Als nächstes wird das NHibernate ISession durch das Verfahren Create schaffen, die die aus dem Kernel ISessionFactory abruft. Die ISession ist auf die Anfrage beschränkt. Dann fragt die Repository-Implementierung einfach nach einer ISession in ihrem Konstruktor.

Auch in meiner App in BeginRequest wird eine ITransaction gestartet, und in EndRequest wird die ITransaction festgeschrieben, um sicherzustellen, dass die Sitzung beibehalten und geschlossen wird.

+0

Hmm, Nun zuerst mit dem Ikernal nicht in der Steuerung. Ich folgte, wo der Autor von pro asp.net mvc 2.0 ihre setzen. Ich bin mir bewusst, SessionFactory ist teuer zu erstellen. Ich dachte, indem ich es in den application_start legte, war es ein guter Platz, da es nur einmal erstellt werden sollte. Ich bin auch verwirrt, wo all dieser Code läuft, geht das in Ihrem Webui-Projekt? Wäre es möglich, ein sehr einfaches Projekt zu sehen, damit ich es mit dem Debugger durchgehen kann. Zum Beispiel sehe ich nicht, wo oder wie das Repository nach der ISession im Konstruktor fragt. – chobo2

Verwandte Themen