Я недавно столкнулся с удивительным поведением EF4, когда после добавления сущности в контекст она недоступна для запросов (ну, вам нужно сделать так, чтобы ваши запросы знали, что вы можете искать в памяти), кроме SaveChanges ().
Позвольте мне немного объяснить наш сценарий: мы используем шаблон UnitOfWork с объектами EF 4.0 и POCO.Недавно мы решили внедрить Message Bus , где мы будем реализовывать в обработчиках сообщений большую часть логики приложения.
Проблема, с которой я столкнулся, заключалась в том, что я передавал свой UnitOfWork (контекстная обертка в нашем случае) в сообщениях.Например, у меня есть логика печати штрих-кода, когда я делаю это, он должен изменить счетчик печати в БД.Печать может выполняться в произвольном порядке для существующего пакета или может выполняться автоматически при создании пакета особого типа.Я прохожу через UnitOfWork, а затем ищу штрих-код с:
public void Handle(IBarCodePrintMessage message)
{
if (message.UnitOfWork == null)
using (var uow = factory.Create<IUnitOfWork>)
{
Handle(message, uow);
uow.Commit();
}
else
Handle(message, message.UnitOfWork);
}
void Handle(IBarCodePrintMessage message, IUnitOfWork uow)
{
// the barcode with the PackageID is in the context or in the db
var barCode = uow.BarCodes.Where(b => b.PackageID == message.PackageID).SingleOrDefault();
barCode.IncreasePrintCount(); // this might be actually quite complex, and sometimes fail
printingServices.PrintBarCode(barCode);
}
Моя проблема в том, что если штрих-код был добавлен в это же самое время, а фиксации еще не было, то это не такнайдено.
Это самый простой пример, у нас есть тонны кода, который выполнял свою собственную фиксацию, и теперь все это нужно выполнить в рамках одной транзакции.
У меня есть пара вопросов на самом деле:
1) Я думал о том, чтобы каким-то образом взломать мой IUnitOfWork, чтобы вернуть набор объектов, которые могут находиться либо в памяти (не зафиксированные изменения), либо в БД (если еще не получены).На самом деле это поведение, которое я ожидаю от моего UnitOfWork, скажите мне, в каком состоянии я нахожусь в последний раз, даже если я еще не зафиксировал, и не предоставляю мне состояние db.Для состояния БД я могу создать другой контекст.
В любом случае это кажется довольно сложным, потому что мне нужно будет реализовать свой собственный тип коллекции сущностей, все методы расширения для него (где сначала выберите select,groupby и т. д.), а затем заставить его работать способом IQueryable (то есть сразу не перечислять таблицы), а затем найти способ сопоставления локально кэшированных и извлеченных сущностей.Мне кажется, это общая проблема, и я думаю, что уже есть реализация, но я не уверен, где.
2) другой вариант - вводить транзакции вручную.Я попробовал его в отношении SQLCE4.0, и это могло бы решить проблему (очень часто вызывать savecontext, чтобы объекты можно было запрашивать из БД, а затем, если возникла какая-либо ошибка, откатить транзакцию), но у меня большие сомнения.Могут быть разные потоки, выполняющие разные транзакции одновременно, не уверен, как они будут взаимодействовать, если откат выполняется.
Также мы используем SQL CE 4.0 и SQL Express 2008 (и то, и другое можно динамически переключать).Начало обработки транзакций таким образом, кажется, приводит к появлению кода DTC, который - я читаю везде - довольно тяжелая вещь, и я бы предпочел избегать.Есть ли способ использовать транзакции простым способом без риска использовать их в DTC?
3) У кого-нибудь есть какие-либо другие варианты или идеи о том, как решить эту проблему?