使用UnitOfWork模式和ApplicationBus的EF4.0 POCO中的简单事务

时间:2011-10-11 16:15:15

标签: c# entity-framework transactions poco unit-of-work

我最近遇到了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)有没有人对如何处理这个问题有任何其他选择或想法?

1 个答案:

答案 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”。