我最近遇到了EF4令人惊讶的行为,在将一个实体添加到上下文之后,它不可用于查询(好吧,你需要知道你的查询,你可能在内存中搜索)除非SaveChanges(被称为。
让我解释一下我们的情景: 我们正在使用带有EF 4.0和POCO对象的UnitOfWork pattern。我们最近决定实现一个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);
}
我的问题是,如果条形码是在同一个uow中添加的,并且还没有提交,那么就找不到了。
这是最简单的示例,我们有大量的代码正在进行自己的提交,现在所有这些都需要在一个事务中进行。
我实际上有几个问题:
1)我正在考虑以某种方式攻击我的IUnitOfWork,返回一组对象,这些对象可能在内存中(不是提交的更改),也可能在DB中(如果尚未检索)。这实际上是一种行为,我期待我的UnitOfWork,告诉我我最后的状态是什么,即使我还没有提交,而不是给我db状态。对于db状态,我可以创建另一个上下文。
无论如何这似乎相当棘手,因为我需要实现我自己的实体集合类型,所有的扩展方法(where,select,first,groupby等),然后让它工作IQueryable方式(意思是它不会立即列出表格),然后找到一种方法来匹配本地缓存的实体和检索到的实体。 对我来说,这似乎是一个普遍的问题,我相信已经有一个实现,只是不知道在哪里。
2)另一种选择是引入手工交易。我尝试对抗SQLCE4.0并且它可能解决了这个问题(经常调用savecontext,因此实体可以从db中查询,然后如果发生任何错误,则回滚事务),但我有很大的疑问。可能有不同的线程同时运行不同的事务,不确定如果回滚它们将如何交互。
我们也使用SQL CE 4.0和SQL Express 2008(两者都可以动态切换)。开始以这种方式处理交易似乎带来了DTC,我在任何地方都读到了 - 这是一件非常沉重的事情,我宁愿避免。有没有办法以简单的方式使用交易而没有将它们用于DTC的风险?
3)有没有人对如何处理这个问题有任何其他选择或想法?
答案 0 :(得分:0)
您可以查询非持久化实体的上下文。
var entity = context.ObjectStateManager
.GetObjectStateEntries(EntityState.Added)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<BarCode>()
.FirstOrDefualt(b => b.PackageId == message.PackageId);
您可以将其更通用并将其合并到您的UoW逻辑中,您将首先检查未保存的实体,如果找不到该实体,您将查询数据库。
无论如何,如果你知道你在下面的处理过程中需要创建一个新的条形码,它应该作为你的界面上公开的属性传递给“message”。