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

默认情况下,实体框架 实现开放式并发模型。 这意味着在查询数据与更新数据之间,不对数据源中的数据保留锁。 实体框架 将对象更改保存到数据库中,但不检查并发。 对于可能出现高度并发的实体,建议为实体在概念层定义一个具有 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. 
    Dim num As Integer = context.SaveChanges()
    Console.WriteLine("No conflicts. " & num.ToString() & " updates saved.")
Catch generatedExceptionName As 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")
End Try
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 值重新加载该对象。

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

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

本节内容

如何:在对象上下文中管理数据并发性(实体框架)

另请参见

概念

使用对象(实体框架)
创建、添加、修改和删除对象(实体框架)