LINQ2SQL采用开放式并发的机制来处理由于数据库并发修改或由于读取和修改之间存在时间差导致的数据不一致的问题。为了实现这一机制,LINQ2SQL在提交数据更改时,会先进行开放式冲突检测,并且当发现冲突后提供了一系列解决冲突的方法。
LINQ2SQL的并发冲突处理采用optimistic concurrency(开放式并发)机制。当发生数据更新时,LINQ2SQL会检查当前数据库值和查询返回的原始值是否相等,如果相等则表示数据库值未发生变化,说明未发生冲突,可以提交更新;否则当数据库值发生变化时,会抛出ChangeConflictException,等待用户决定如何处理更新。
参考资料:
开放式并发概述 http://msdn.microsoft.com/zh-cn/library/bb399373.aspx
本文会用到一些名词,为避免大家误解,先说明如下,对于某个entity object的属性:
1) 数据库值:当并发冲突发生时,数据库保存的字段值
2) 原始值:通过DataContext查询获得的字段值。由于从DataContext查询到数据更新存在时间间隔,所以原始值与数据库值可能不同。
当前值:通过entity.Property可获取的属性值。刚从DataContext查询时,当前值=原始值,但在某些操作中可能修改了当前值,所以当前值和原始值可能不同。
开放式冲突检测
可能引发Optimistic Concurrency的只有涉及Update和Delete的操作,LINQ通过执行Update或Delete的SQL语句的操作返回值(@@ROW_COUNT)来检测是否产生冲突。
我们来执行下面的代码(使用Northwnd数据库):
1 var context = GenerateContext();
2 context.Log = Console.Out;
3 Customer customer = context.Customers.First();
4 customer.CompanyName = "Updating customer";
5 context.SubmitChanges();
产生的SQL语句如下,注意看Where子句和传递的参数
01 UPDATE [dbo].[Customers]
02 SET [CompanyName] = @p10
03 WHERE ([CustomerID] = @p0) AND ([CompanyName] = @p1) AND ([ContactName] = @p2) A
04 ND ([ContactTitle] = @p3) AND ([Address] = @p4) AND ([City] = @p5) AND ([Region]
05 IS NULL) AND ([PostalCode] = @p6) AND ([Country] = @p7) AND ([Phone] = @p8) AND
06 ([Fax] = @p9)
07 -- @p0: Input NChar (Size = 5; Prec = 0; Scale = 0) [ALFKI]
08 -- @p1: Input NVarChar (Size = 19; Prec = 0; Scale = 0) [Alfreds Futterkiste]
09 -- @p2: Input NVarChar (Size = 12; Prec = 0; Scale = 0) [Maria Anders]
10 -- @p3: Input NVarChar (Size = 20; Prec = 0; Scale = 0) [Sales Representative]