保存更改和管理并发(实体框架)
实体框架 实现开放式并发模型。这意味着不对数据源中的数据保留锁。但是默认情况下,对象服务将对象更改保存到数据库中,而不检查并发。对于可能高度并发的属性 (Property),建议在概念层定义实体属性 (Property),并设置属性 (Attribute) 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 ex 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 更新对象上下文中的已添加对象。而应使用 MergeOption 的 OverwriteChanges 值重新加载该对象。
有关管理对象上下文的更多信息,请参见如何:在对象上下文中管理数据并发性(实体框架)。
对象服务还支持通过用 System.Transactions 命名空间定义的事务。有关更多信息,请参见在对象服务中管理事务(实体框架)。