VictorStone

导航

 

保存更改和管理并发(实体框架)

默认情况下,实体框架 实现开放式并发模型。 这意味着在查询数据与更新数据之间,不对数据源中的数据保留锁。 实体框架 将对象更改保存到数据库中,但不检查并发。 对于可能出现高度并发的实体,建议为实体在概念层定义一个具有 ConcurrencyMode="fixed" 特性的属性,如下例中所示:

<Property Name="Status" Type="Byte" Nullable="false" ConcurrencyMode="Fixed" />

在使用此特性时,实体框架 会检查数据库中的更改,然后再将更改保存到数据库中。 任何有冲突的更改都会引发 OptimisticConcurrencyException 有关更多信息,请参见如何:在对象上下文中管理数据并发性(实体框架) 定义使用存储过程更新数据源的 实体数据模型 时,也可能引发 OptimisticConcurrencyException 在这种情况下,如果用于执行更新的存储过程报告更新了零行,则会引发该异常。

在高度并发情况下进行更新时,建议经常调用 Refresh 在调用 Refresh 时,RefreshMode 将控制传播更改的方式。 StoreWins 选项将导致实体框架 使用数据库中的相应值覆盖对象缓存中的所有数据。 相反,如果使用 ClientWins 选项,则将使用数据源中的最新值替换缓存中的原始值。 这样,通过消除缓存数据的更改与数据源中相应数据的更改之间的冲突,可以确保对象缓存中更改过的所有数据都可以成功地保存回数据源。

如果数据源更新可能会修改属于对象上下文中其他对象的数据,则应在调用 SaveChanges 方法后调用 Refresh 方法。 例如,在 AdventureWorks 销售模型中添加新的 SalesOrderDetail 时,会触发 SubTotal 列的更新以反映添加新项后的小计。 在这种情况下,应调用 Refresh 方法并传递订单的 SalesOrderHeader 对象。 这样可确保将触发器生成的值发送回对象上下文中的 SalesOrderHeader 对象。

实体框架 跟踪已对缓存中的对象所做的更改。 调用 SaveChanges 方法时,实体框架 会尝试将更改合并回数据源。 如果对象缓存中的数据更改与对象添加到缓存后或在缓存中刷新后数据源中发生的更改相冲突,则 SaveChanges 会失败,并引发 OptimisticConcurrencyException 这会导致整个事务回滚。 如果发生 OptimisticConcurrencyException,应通过调用 Refresh 并指定是否解决冲突(通过将数据保存到对象数据 (ClientWins) 或通过使用数据源数据更新对象缓存 (StoreWins))来处理该异常,如下面的示例所示:

try
{
    // Try to save changes, which may cause a conflict.
    int num = context.SaveChanges();
    Console.WriteLine("No conflicts. " + num.ToString() + " updates saved.");
}
catch (OptimisticConcurrencyException)
{
    // Resolve the concurrency conflict by refreshing the 
    // object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders);

    // Save changes.
    context.SaveChanges();
    Console.WriteLine("OptimisticConcurrencyException " + "handled and changes saved");
}

如果不能在数据源中成功创建添加到 ObjectContext 中的对象,则 SaveChanges 会引发 UpdateException 如果具有关系所指定的外键的行已存在,则会出现这种情况。 如果出现这种情况,就不能使用 Refresh 更新对象上下文中的已添加对象。 而应使用 MergeOptionOverwriteChanges 值重新加载该对象。

有关管理对象上下文的更多信息,请参见如何:在对象上下文中管理数据并发性(实体框架)

您可以选择将事务用作开放式并发的替代选项。 有关更多信息,请参见管理连接和事务(实体框架)

 

MergeOption的说明:

 成员名称说明
  AppendOnly 对象上下文中不存在的对象将附加到该上下文。 如果该上下文中已存在对象,则该项中对象属性的当前值和原始值不会被数据源值覆盖。 该对象的项状态和项中对象的属性状态不会更改。 AppendOnly 是默认合并选项。
  NoTracking 对象保持为 Detached 状态,且未在 ObjectStateManager 中跟踪对象。 但是,Entity Framework 生成的实体和具有代理的 POCO 实体将维护对该对象上下文的引用以便于相关对象的加载。
  OverwriteChanges 对象上下文中不存在的对象将附加到该上下文。 如果该上下文中已存在对象,则该项中对象属性的当前值和原始值将会被数据源值覆盖。 该对象的项状态将设置为 Unchanged,任何属性都不会标记为已修改。
  PreserveChanges 对象上下文中不存在的对象将附加到该上下文。

如果该实体的状态为 Unchanged,那么该输入中的当前值和原始值会被数据源值覆盖。 实体的状态仍保持 Unchanged,并且属性没有标记为已修改。

如果该实体的状态为 Modified,那么修改的属性的当前值不会被数据源值覆盖。 数据源中的值将覆盖原始的未修改属性的值。

在 .NET Framework 4 版中,Entity Framework 比较未修改的属性的当前值和从数据源返回的值。 如果这些值不相同,那么该属性将标记为已修改。

在 .NET Framework 3.5 SP1 版中,即使数据源中的值不同,Entity Framework 也不会将该属性标记为已修改。

当调用 SaveChanges 时,只有修改过的属性才会保留到数据源。

若要保留 3.5 SP1 行为,请将 UseLegacyPreserveChangesBehavior 设置为 true PreserveChanges 选项可用于在保留本地上下文中的更改的同时解决开放式并发异常。 有关更多信息,请参见Saving Changes and Managing Concurrency (Entity Framework)

posted on 2013-08-17 13:55  VictorStone  阅读(1420)  评论(0编辑  收藏  举报