对象缓存的第二个好处就是避免了同一个DataContext在SubmitChanges时发生optimistic concurrency的情况,相关例子在“LINQ那些事(4)”中已经提过。
很多人会质疑O/R Mapping框架在运行时通过反射来映射对象,会造成性能的降低。这个问题是不可避免的,问题是影响的程度,LINQ2SQL我还没有在具体的项目中应用,问了TerryLee他的项目也没在用,希望有应用经验的朋友能告诉我一下。
改变跟踪(change tracking)
同样的先由一段代码,我们看看change tracking的好处:
1 var context = GenerateContext();
2 context.Log = Console.Out;
3 var query =
4 (from c in context.Products
5 select c).First();
6 query.ProductName = "foo";
7 context.SubmitChanges();
代码从northwnd数据库中取出一条product记录,修改了ProductName后提交数据库保存,看看输出的SQL语句:
01 UPDATE [dbo].[Products]
02 SET [ProductName] = @p9
03 WHERE ([ProductID] = @p0) AND ([ProductName] = @p1) AND ([SupplierID] = @p2) AND
04 ([CategoryID] = @p3) AND ([QuantityPerUnit] = @p4) AND ([UnitPrice] = @p5) AND
05 ([UnitsInStock] = @p6) AND ([UnitsOnOrder] = @p7) AND ([ReorderLevel] = @p8) AND
06 (NOT ([Discontinued] = 1))
07 -- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
08 -- @p1: Input NVarChar (Size = 4; Prec = 0; Scale = 0) [Chai]
09 -- @p2: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
10 -- @p3: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
11 -- @p4: Input NVarChar (Size = 18; Prec = 0; Scale = 0) [10 boxes x 20 bags]
12 -- @p5: Input Money (Size = 0; Prec = 19; Scale = 4) [18.0000]
13 -- @p6: Input SmallInt (Size = 0; Prec = 0; Scale = 0) [39]
14 -- @p7: Input SmallInt (Size = 0; Prec = 0; Scale = 0) [0]
15 -- @p8: Input SmallInt (Size = 0; Prec = 0; Scale = 0) [10]
16 -- @p9: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [foo]
17 -- Context: SqlProvider(Sql2008) Model: MappedMetaModel Build: 3.5.30729.1
SET语句中只包含已修改的属性,优化了UPDAte语句;Where语句为原始值和数据库值的比较,实现了并发检测。
在返回查询对象之前,DataContext会保存一份对象的copy,并通过change tracking获知对象发生修改,基于这两点DataContext才能生成上面的SQL语句。
在DataContext对象的生命周期内,identity caching和change tracking给我们不少好处,但是这样的好处是以牺牲少许性能为代价的,对于常用的查询-显示模式的应用,可以通过关闭这两个服务来提高性能。