Когда мне нужно сбросить Rhino Commons UnitOfWork? - PullRequest
2 голосов
/ 19 марта 2009

При использовании 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 не должен быть в состоянии решить, когда очистить себя? Или я что-то недопонимаю?

Ответы [ 3 ]

2 голосов
/ 25 марта 2009

Хорошо, кажется, что хотя вызов 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 будут проверять последние данные.

1 голос
/ 19 марта 2009

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

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

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

ОБНОВЛЕНИЕ:

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

SELECT * FROM Car

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

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

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

0 голосов
/ 20 марта 2009

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

...