LINQ TO SQL 注意事项

LINQ,语言集成查询(Language-Integrated Query)。是VS 2008中引入的新特性,为C#和VB提供了强大的查询功能。在网上大家对LINQ褒贬不一,但我觉得它至少可以做到编写更少的代码创建完整的应用,缩短了开发周期,这一点就很吸引我这种懒人了!我也知道LINQ比起ADO.NET性能上会差一些,但我做的都不是什么大型项目,这点差距应该是可以忽略不计的。一直以来,主要接触的是LINQ to SQL,虽然并没有玩转它,也还是积累了一点东西。

不要将DataContext单例化

单个DataContext最大的问题就是SubmitChanges造成当前线程和数据库的数据不同步。DataContext不是线程安全的对象,由于会缓存所有的数据操作,当A线程的数据修改到一半,它可能被B线程在调用SubmitChanges时提交了,这个问题在开发时不容易被发现。之前我在项目中用了单例模式创建DataContext,导致出现用户反应“为什么我在这篇文章的评论会跑到别的文章下面去了?!”之类的问题,正是因为这个原因。DataContextLINQ to SQL框架的主入口点,它拥有所有表的映射让我觉得会占用很多资源所以我用单例模式创建它。通过分析源代码得出结论:“DataContext并没有占用多么庞大的资源,无非就是一个DbConnection和一些映射对象而已。”,我才知道那只是映射,没有任何数据。MSDN上也提示:“请不要试图重用DataContext的实例。每个DataContext都会保持对应一个特定编辑/查询会话的状态(包括标识缓存)。若要获取基于数据库当前状态的新实例,请使用新的DataContext。”

因此,DataContext是不应该被单例化或是静态化的。DataContext是轻量级的资源,创建它不需要很大的开销,最佳实践是为每个操作创建新的DataContext实例。

禁用ObjectTrackingEnabled

       DataContext的ObjectTrackingEnabled设为false这样减少了要跟踪的项目,可以提高检索时的性能,但禁用对象跟踪时,要特别注意:

(a)只是推荐在查询的情况下禁用;

(b)必须在执行查询前禁用

(c)禁用之后不能再调用AttachSubmitChanges方法。

添加IsDbGenerated=true

默认情况下,LINQ添加对象时,数据库中设置的默认值会失效。例如:ModifiedTime是数据库中使用getDate()为默认值的,如果没有为对应的实体属性添加IsDbGenerated=true, 则数据库中的getDate()将失效。

为实体添加RowVersion成员                                  

      对于在不同的DataContext之间,使用Attach方法来更新数据,但是Attach方法不能附加一个修改过的实体,除非该实体包含RowVersion成员。

实现RowVersion成员的方法有两种:

       (1)为数据库表定义一个timestamp列;

       (2)在表主键所对应的实体属性上,定义IsVersion=true特性。

注意,两种方法不能同时使用,否则将抛出InvalidOperationException:成员“System.Data.Linq.Binary timeStamp和“Int32 XXId”都标记为行版本。

       LINQ默认采用“乐观式并发”的策略处理更新数据时的并发冲突。在乐观式并发中,Where子句不只是包含主键字段,还会加入除更新字段外的所有字段,作为Update语句的Where条件。在调用DataContext的SubmitChanges方法时,若Update语句在更新过程中产生了冲突,就会抛出“找不到行或行已更改”的异常。在默认情况下,实体属性的UpdateCheck都设置为UpdateCheck.Always,表示LINQ to SQL将用该属性检查乐观式并发。乐观式并发的参数数量过多,会导致不必要的性能消耗,因此需要修改映射规则,只让部分属性参与到并发检查中。

       若在数据表中有timestamp列,实体属性的UpdateCheck会默认设置为UpdateCheck.Never,若使用IsVersion作为更新检查依据,则必须在实体属性上(主键除外)手动设置UpdateCheck.Never来避免更新检查,但是数据库表结构更新,再重新生成dbml的话,手动设置的IsVersion=trueUpdateCheck.Never都将消失不见。所以推荐使用timestamp作为更新检查依据,我想主键列和timestamp列还是各司其职比较好些。为所有数据表创建一个timestamp列,在处理并发的时候,LINQ to SQL不需要检查所有的字段,这样可以提高系统的性能

AutoSync特性的作用

       对于表主键对应的实体属性,AutoSync会默认设置为AutoSync.OnInsert,它的作用就是Insert一个对象时,当调用DataContextSubmitChanges方法后,主键对应的属性值会被自动填充。

不需要手动执行DataContextDispose方法

DataContextSubmitChanges方法的finally块中调用了SqlConnection.Close方法;而执行查询的DataContext.ExecuteQuery方法到最后也会调用SqlConnectionManager.ReleaseConnection方法。在我们手动执行DataContext.Dispose时,主要工作已经执行完了,并且SqlConnectionManager.ReleaseConnection方法所执行的内容比SqlConnection.Close方法要多。

因此,在使用LINQ to SQL时,完全没必要手动执行DataContext.Dispose方法或是使用using语句。

posted @ 2012-01-29 16:49  iceknp  阅读(1800)  评论(1编辑  收藏  举报