Дизайн приложения: управление NH-сессиями, общий репозиторий, ASP.NET MVC - PullRequest
1 голос
/ 24 января 2012

Определив domain model, я хочу выяснить, как выполнять остальную часть работы.


Слой доступа к данным

Я читал ранее, что нет необходимости кодировать собственную реализацию UnitOfWork поверх ISession (хотя я нашел много информации о том, как это сделать довольно хорошо). Так что я совсем запутался .. У меня есть интерфейс хранилища, подобный этому:

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? Как?

Спасибо, что прочитали вопрос-монстр! Ваше руководство приветствуется!

Ответы [ 4 ]

2 голосов
/ 25 января 2012

Как обрабатывать инъекционные зависимости с помощью mvc, зависит от версии, но всегда помогает использовать реальный контейнер Dependency Injection (DI). Как бы вы ни разрезали его, это решение потребует от вас внедрения ISession в репозиторий, а не ISessionFactory. Это позволяет вашему DI-контейнеру правильно управлять временем жизни сеанса.

Предполагая, что вы используете Asp.Net MVC 3 и у вас нет подключения к конкретному контейнеру 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;
    }
}

Что касается репозитория, я хотел бы указать вам на отличную запись в блоге Репозиторий - это новый синглтон

1 голос
/ 24 января 2012

В веб-приложениях вы должны использовать шаблон NH session для каждого веб-запроса. Я думаю, что у вас должен быть только один сеанс на каждый веб-запрос, и ваши репозитории должны использовать этот единственный сеанс. Для реализации этого вам нужно написать IHttpModule, который откроет сеанс, начнет транзакцию и связывает сеанс как окружающий (текущий) сеанс, когда запрос начинается, и заканчивает транзакцию и закрывает сеанс, когда запрос заканчивается. Вам также нужно установить current_session_context_class в «web». Тогда ваш репозиторий / DAO будет выглядеть так

    public TEntity Get(object id)
    {
        return sessionFactory.GetCurrentSession().Get<TEntity>(id);
    }
1 голос
/ 24 января 2012

Я обычно использую свойство только для чтения в своем репозитории, например,

    protected  ISession Session
    {
        get
        {
            return NHibernateSessionFactory.CurrentFor(dataBaseFactoryKey);
        }
    }

Мой NHibernateSessionFactory работает как this .

0 голосов
/ 24 января 2012

Лучший шаблон с MVC и NHibernate - это сеанс на запрос.
шаги:

  1. В Global.asax добавьте общедоступную статическую ISessionFactory SessionFactory ;
  2. В Application_Start () настроить и построить фабрику сеанса:

    var config = новая конфигурация (). Configure ();
    SessionFactory = config.BuildSessionFactory ();

  3. В Application_BeginRequest открыть сеанс и связать его с CurrentSessionContext:

    var nhSession = SessionFactory.OpenSession ();
    CurrentSessionContext.Bind (Session);

  4. In Application_EndRequest () открепить и удалить сеанс

Теперь в вашемКонтроллер, к которому вы можете обратиться, вызывая сеанс:

Global.SessionFactory.GetCurrentSession();

РЕДАКТИРОВАТЬ: После комментария @hival

Внутри вашего контроллера обработайте вашу модель в блоке using и выполните коммит / откатосновываясь на вашей логике.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...