Как сохранить IQueryable <> в транзакции, используя шаблон репозитория? - PullRequest
7 голосов
/ 15 сентября 2010

Согласно NHProf, использование неявных транзакций не рекомендуется:

http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions

Однако NHibernate LINQ возвращает IQueryable<> при чтении объектов из базы данных, иэто лениво оценивается.У меня есть этот метод в хранилище:

public IQueryable<T> GetAll<T>()
{
    using (var transaction = _session.BeginTransaction())
    {
        var data = _session.Linq<T>();
        transaction.Commit();
        return data;
    }
}

Проблема здесь в том, что метод будет совершать транзакцию до оценки data.Есть ли способ использовать шаблон хранилища и сохранить IQueryable<> в явной транзакции?Или для операций чтения допустимо использование неявных транзакций?

Ответы [ 3 ]

5 голосов
/ 16 сентября 2010

Хранилище должно не создавать транзакцию.Это ответственность отдельного уровня (который зависит от типа приложения).

3 голосов
/ 16 сентября 2010

Я бы реорганизовал это, чтобы позволить внешний контроль транзакций. Репозиторий не может знать объем единицы работы, частью которой являются различные вызовы чтения / записи, если только код, который выполняет вызовы, не сообщает об этом. Рассмотрите возможность настройки шаблона «единица работы»: не раскрывая конкретных деталей реализации хранилища данных, разрешите объектам, зависящим от репозитория, указать, что они начинают, отменяют или завершают «единицу работы».

public interface IRepository
{
   public UnitOfWork BeginUnitOfWork()

   public void CommitUOW(UnitOfWork unit)

   public void AbortUOW(UnitOfWork unit)

   public IQueryable<T> GetAll<T>(UnitOfWork unit)

   public List<T> GetAll<T>()

   public void Store<T>(T theObject, UnitOfWork unit)

   public void Store<T>(T theObject)
}

Ваш репозиторий, вероятно, реализовал бы это, поддерживая частный словарь транзакций SQL, каждая из которых привязана к объекту UnitOfWork (это может быть так же просто, как пустой экземплярный класс, или он может предоставлять независимую от фреймворка информацию о состоянии или показателях). При выполнении операции с БД ваши абоненты сначала попросят начать UoW, и им будет выдан токен, который они будут использовать для идентификации контекста, в котором они делают вызов БД. Объект, который получает токен, может передать его другим классам, которые должны выполнять операции с БД в том же рабочем контексте. Единица работы будет оставаться открытой до тех пор, пока зависимый класс не сообщит репозиторию, что он завершен, что позволяет выполнять ленивые нагрузки и атомарные многооперационные процедуры.

Обратите внимание, что существуют перегрузки, которые не требуют единиц работы. Можно и возможно необходимо совершать простые вызовы без явного запуска единицы работы. В этих случаях ваш репозиторий может создать внутреннее UOW, выполнить запрошенную операцию и вернуть результаты. Однако, ленивая загрузка будет трудной или невозможной в этих случаях; вам придется извлечь весь набор результатов в список перед завершением внутреннего UoW.

1 голос
/ 16 сентября 2010

Я с Диего на этом - хранилище не может знать объем транзакции.

У меня также есть проблема с возвратом IQueryable - насколько я понимаю, он имеет массу дополнительных методов запросов, которые могут быть очень сложны для модульного тестирования. Я предпочитаю возвращать IEnumerable и инкапсулировать более сложные запросы в методы репозитория. В противном случае вам придется выполнить модульное тестирование всех видов вариаций запросов по сравнению с выводом GetAll ().

...