Вопрос

При использовании Rhino Commons UnitOfWork (в UnitOfWorkApplication для ASP-MVC) мне нравится использовать статический класс Rhino Repository для сохранения таких сущностей:

Repository<Car>.Save(new Car(Id = 1));

Я обнаружил, что могу вывести объект сразу после этого вызова, используя:

Car car = Repository<Car>.Get(1);

Это работает нормально.Однако когда я использую поставщика NHibernate Linq в Rhino UnitOfWork следующим образом:

var allCars = (from rep in UnitOfWork.CurrentSession.Linq<Car>()
               select rep).ToList();

Я получаю пустой список.Кажется, мне нужно вызвать UnitOfWork.Current.Flush(), прежде чем я смогу вытащить машину вот так.Я не понимаю почему, учитывая, что за кулисами я предполагаю, что оба метода поиска запрашивают один и тот же сеанс/единицу работы.Означает ли это, что вам следует вызывать UnitOfWork.Current.Flush() после каждого сохранения в базу данных?Разве NHibernate не должен уметь определять, когда сбрасывать себя?Или я что-то не понимаю?

Это было полезно?

Решение

Хорошо, похоже, что хотя вызов Get в репозиторий может использовать кеш сеанса, он может «видеть» сохраненный автомобиль в кеше:

Car car = Repository<Car>.Get(1); // This works because it uses the same session

Запрос linq НЕ использует кэш сеанса:

var allCars = (from rep in UnitOfWork.CurrentSession.Linq<Car>()               
select rep).ToList(); // Does not work, even if it is in the same code block and even though it uses the same session

Поэтому передовой практикой является то, что любые изменения базы данных (сохранение, обновление, удаление, вставка) должны сопровождаться:

UnitOfWork.Session.Flush(), 

или завернутый в:

With.Transaction(delegate{
   // code here
})

или украсьте свой метод [Транзакцией] и используйте банкомат.Это гарантирует, что последующие запросы linq будут проверять актуальные данные.

Другие советы

Когда вы вызываете Repository.Save, вы уведомляете сеанс, проводимый репозиторием, о необходимости отслеживать этот объект и синхронизировать изменения в базе данных при следующем сбросе.Пока вы не очистите сеанс, в базу данных не вносятся никакие изменения.Однако объект становится частью кэша сеанса и поэтому будет возвращен функцией Get(1).

Когда вы запускаете запрос на заполнение коллекции, сеанс запрашивает базу данных, чтобы получить результаты, если только она еще не кэшировала эти результаты. Поскольку вы еще не обновили базу данных, автомобиль, добавленный вами в сеанс, не будет частью набора результатов. (<-- Возможно, неверно). Если я правильно читаю документацию, как результаты запроса, так и объекты с сохранением() должны быть добавлены в кэш сеанса (первого уровня).Это не обязательно означает, что querystatement.List() запрашивает кеш после добавления результатов БД...Мне трудно уяснить себе, что именно происходит.

Кроме того, я считаю, что вы можете настроить автосброс сеанса, но мне придется проверить документацию.

ОБНОВЛЯТЬ:

Думаю, я смогу увидеть, что здесь происходит.Сеанс по умолчанию FlushMode является Auto но Рино UnitOfWork.Start() создает сеанс с FlushMode установлен в Commit, что означает, что сеанс не будет автоматически сброшен, если вы явно не вызовете Flush() или зафиксировать транзакцию.С FlushMode из Auto, NHibernate (иногда?) очищает сеанс перед запросом, чтобы предотвратить возврат устаревших данных.Если я прав, ваша транзакция с БД выглядит примерно так:

SELECT * FROM Car

INSERT INTO Car (...) VALUES (...)

Когда он автоматически сбрасывается, кажется немного двусмысленным из документации/блогов, которые я прочитал...Самый распространенный ответ заключается в том, что это с FlushMode = Auto он сбрасывает "иногда", хотя и гарантирует, что Session.Find никогда не вернет устаревшие данные.Поскольку NHibernate Linq на самом деле просто создает запрос критериев, он может не вызвать автоматическую очистку (возможно, сейчас это исправлено...это трудно узнать).

Мне кажется, что в вашем случае вы хотите выполнить сброс после сохранения, потому что хотите сразу получить результаты сохранения.В небольшой единице работы, где вы только обновляли сущности, достаточно одного Commit().Может быть UnitOfWork.CurrentSession.FlushMode = FlushMode.Auto; могло бы помочь, но тот факт, что UOW Factory явно устанавливает режим Commit, похоже, побуждает вас серьезно задуматься о границах вашего UOW.

Благодаря Стюарту Чайлдсу, я подозреваю, что он прав в том, что проблема может быть связана с провайдером NHibernate Linq.Я не уверен, что он делает за кулисами, но он может использовать другой сеанс. Если это так, то имеет смысл очистить хранилище репозитория, прежде чем запрос Linq «увидит» его.Пришло время просмотреть исходный код, но мне сказали, что у меня просто расплавится голова, если я попытаюсь его понять!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top