Как мне настроить мой репозиторий с помощью свободно используемого nhibernate? - PullRequest
1 голос
/ 14 января 2011

Я пытаюсь использовать шаблон репозитория, предназначенный для DI с беглым 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();
            }

        }
    }

Здесь я настраиваю свои вещи. Я сделал метод, который настраивает бегло. Насколько я понимаю, это должно происходить только один раз для каждого веб-запроса (что, я думаю, так и происходит, так как это вызывает только при запуске приложения)

Я не уверен, что мой метод 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 ().

Мой домашний контроллер

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

Как я уже сказал, я бы хотел избавиться от этого метода, но я не уверен, как перенести сеанс в репозитории. Так что, пока кто-то не покажет мне, я думаю, что сейчас я должен сделать это так.

1 Ответ

3 голосов
/ 15 января 2011

Во-первых, вы можете рассмотреть возможность использования расширения Ninject.Web.Mvc, поскольку оно уже имеет NinjectControllerFactory и приложение NinjectHttpApplication, которое подключает фабрику контроллеров. это также позволяет вам создавать IKernel в вашем приложении, где оно должно быть, а не на фабрике контроллеров.

во-вторых, создание SessionFactory очень дорого, поэтому его следует делать ОДИН РАЗ в течение всего срока службы приложения, т. Е. 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. Провайдер просто создает 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 фиксируется, чтобы сеанс сохранялся и закрывался.

...