【问题标题】:Simple transactions in EF4.0 POCO with UnitOfWork pattern and ApplicationBusEF4.0 POCO 中具有 UnitOfWork 模式和 ApplicationBus 的简单事务
【发布时间】:2011-10-11 16:15:14
【问题描述】:

我最近遇到了 EF4 令人惊讶的行为,在将实体添加到上下文后,它无法用于查询(嗯,您需要让您的查询知道,您可能正在内存中搜索),除非 SaveChanges( ) 被调用。

让我解释一下我们的场景: 我们将 UnitOfWork pattern 与 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);
}

我的问题是,如果条形码是在同一个 uow 中添加的,并且还没有提交,那么它就找不到了。

这是最简单的例子,我们有大量代码在进行自己的提交,现在所有这些都需要在一个事务下进行。

其实我有几个问题:

1) 我正在考虑以某种方式破解我的 IUnitOfWork,以返回一组对象,这些对象可能在内存中(未提交的更改)或数据库中(如果尚未检索)。这实际上是我希望我的 UnitOfWork 的一种行为,告诉我我处于的最后一个状态是什么,即使我还没有提交,也不要给我 db 状态。对于 db 状态,我可以创建另一个上下文。

无论如何这似乎很棘手,因为我需要实现我自己类型的实体集合,它上面的所有扩展方法(where、select、first、groupby 等),然后让它工作 IQueryable方式(意味着它不会立即列出表),然后找到一种方法来匹配本地缓存的实体和检索到的实体。 对我来说,这似乎是一个普遍的问题,我相信已经有一个实现,只是不确定在哪里。

2) 另一种选择是引入手动交易。我对 SQLCE4.0 进行了尝试,它可能会解决问题(经常调用 savecontext,因此可以从数据库中查询实体,然后如果发生任何错误,则回滚事务),但我有很大的疑问。可能有不同的线程同时运行不同的事务,不确定如果一个回滚它们将如何交互。

我们还使用 SQL CE 4.0 和 SQL Express 2008(两者都可以动态切换)。开始以这种方式处理交易似乎会带来 DTC,我到处都读到它是一件相当沉重的事情,我宁愿避免。有没有一种方法可以轻松地使用交易,而不会将交易用于 DTC?

3) 是否有人对如何解决此问题有任何其他选择或想法?

【问题讨论】:

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


    【解决方案1】:

    您可以查询未持久化实体的上下文。

    var entity = context.ObjectStateManager
                        .GetObjectStateEntries(EntityState.Added)
                        .Where(e => !e.IsRelationship)
                        .Select(e => e.Entity)
                        .OfType<BarCode>()
                        .FirstOrDefualt(b => b.PackageId == message.PackageId);
    

    您可以使其更通用并将其合并到您的 UoW 逻辑中,您将首先检查未保存的实体,如果找不到实体,您将查询数据库。

    无论如何,如果您知道您创建了一个新的条形码,该条形码将在以下处理中使用,它应该作为在您的界面上公开的属性在“消息”中传递。

    【讨论】:

    • 是的,我知道这是可行的,但显然这意味着我需要更改我的服务层中的所有查询以首先查看内存,我正在考虑一个更通用的解决方案,其中uow.BarCodes 会给我一个 IQueryable,它会透明地搜索内存,或者如果没有找到数据库。但我不确定该实现会是什么样子......
    • 我也不能将条形码作为属性传递,因为在某些情况下我只能得到带有 PackageID 的打印指令
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-09
    • 2012-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多