Entity framework 4 模式以克服缺少冲突模式的缺陷。是否在实体框架中继续冲突实现?

Entity framework 4 模式以克服缺少冲突模式的缺陷。是否在实体框架中继续冲突实现?,entity-framework-4,batch-processing,optimistic-concurrency,Entity Framework 4,Batch Processing,Optimistic Concurrency,Linq To SQL的DataContext在SubmitChanges上有一个重载,允许在抛出乐观并发异常时继续进行更新,并为开发人员提供了一种机制来解决以后的冲突 即使是WCFDataServicesContext也为其SaveChanges方法提供了一个SaveChangedOptions.ContinueOnError参数,该参数至少允许您在发生错误时继续更新,并使冲突的更新无法解决,以便您以后可以查看它们 (1) 那么为什么ObjectContext.SaveChanges方法没有这

Linq To SQL的
DataContext
SubmitChanges
上有一个重载,允许在抛出乐观并发异常时继续进行更新,并为开发人员提供了一种机制来解决以后的冲突

即使是
WCFDataServicesContext
也为其
SaveChanges
方法提供了一个
SaveChangedOptions.ContinueOnError
参数,该参数至少允许您在发生错误时继续更新,并使冲突的更新无法解决,以便您以后可以查看它们

(1) 那么为什么
ObjectContext.SaveChanges
方法没有这样的选项呢

(2) 是否存在模仿Linq到SQL行为的更新模式?我在MSDN上找到的例子使它看起来好像在多次更新的情况下会看到你回家。但这种模式不允许您单独调查每个冲突的更新:它只是提醒您第一个冲突,然后让您可以选择“一次扫描清除表”,以防止出现任何进一步的乐观并发异常,如果你不知道是否存在,以及你想对它们做些什么

那么为什么ObjectContext.SaveChanges方法没有这样的选项呢

我认为最简单的答案是因为LINQtoSQL、实体框架和WCF数据服务都是由不同的团队实现的,这些团队之间的内部通信并不像我们希望的那样有效。我已经在中描述了新API中缺少的一些有趣的特性,但我不认为这是一个缺少的特性-我将在回答的第二部分解释它

WCF数据服务具有更有趣的特性,这些特性也应该是实体框架的一部分。例如:

  • 多个查询和SaveChanges操作可用于对服务器的单个调用
  • -这将以异步/等待实现的形式出现在EF6中
是否存在模仿Linq到SQL行为的更新模式

有一种模式可以解决这个问题,但你可能不喜欢它。EF的
SaveChanges
作为工作单元工作。它要么保存所有更改,要么不保存任何更改。如果您的保存操作可能导致仅保留部分更改,则不应通过单个
SaveChanges
调用来处理。每个原子更改集都应该有自己的
SaveChanges
调用:

using (var scope = new TransactionScope(...)) {
    foreach (var entity in someEntitiesToModify) {
        try {
            context.SomeEntities.Attach(entity);
            context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
            context.SaveChanges();
        catch (OptimisticConcurrencyException e) {
            // Do something here 

            context.Refresh(e.StateEntries[0].Entity, RefreshMode.ClientWins);
            context.SaveChanges();
        }
    }

    scope.Complete();
}
我认为这个特性不存在的原因是因为它不是泛型的,正如前面提到的,它违背了工作单元模式。假设这个例子:

  • 加载一个实体
  • 将新的从属实体添加到加载实体的导航属性中
  • 在加载的实体上更改某些内容
  • 同时,其他人会同时删除您加载的实体
  • 您可以通过轻松的冲突解决方案触发SaveChanges
  • EF将尝试保存对主体实体的更改,但会发生冲突,因为数据库中没有要更新的实体
  • EF将继续,因为冲突解决变得轻松
  • EF将尝试插入依赖实体,但它将触发
    SqlException
    ,因为数据库中不存在主体实体。此异常将破坏持久性操作,您将不知道为什么它会抱怨引用完整性,因为您有一个主体实体。(由于上下文的内部状态不一致,此插入甚至可能不会发生,EF引发另一个异常,但这取决于EF的内部实现)
这立即使冲突解决的整个过程变得更加复杂。有三种解决方法:

  • 根本不支持它。如果您需要每个实体的冲突解决方案,您仍然可以使用我上面展示的示例,但对于复杂场景,它可能不起作用,因为复杂场景很难解决
  • 每次发生冲突时重新生成数据库更改集—这意味着探索剩余的更改集,并从已处理的持久性中排除与冲突实体及其关系相关的所有实体。存在一个问题:EF无法从处理中排除任何已更改的实体。这会破坏工作单位的意义,我再重复一次:放松冲突解决也会破坏工作单位的意义
  • 让EF继续处理依赖项,即使主体实体发生冲突。这需要处理数据库异常并了解其内容,以了解异常是由于主体冲突还是由于其他错误(应立即使整个持久性操作失败)引发的。在代码级别上理解数据库异常可能非常困难,而且它对于每个受支持的数据库都是特定于提供者的
这并不意味着不可能实现这样的功能,但当涉及到关系时,它需要覆盖所有场景,这可能相当复杂。我不确定linqtosql是否能处理这个问题

你可以随时就或提出建议,并尝试自己实施。也许我觉得这个功能太复杂了,很容易实现