这里有一个小实验我做:
MyClass obj = dataContext.GetTable<MyClass>().Where(x => x.ID = 1).Single();
Console.WriteLine(obj.MyProperty); // output = "initial"
Console.WriteLine("Waiting..."); // put a breakpoint after this line
obj = null;
obj = dataContext.GetTable<MyClass>().Where(x => x.ID = 1).Single(); // same as before, but reloaded
Console.WriteLine(obj.MyProperty); // output still = "initial"
obj.MyOtherProperty = "foo";
dataContext.SubmitChanges(); // throws concurrency exception
当我打的断点3行后,我去一个SQL查询窗口并手动更改为“更新”的值。 然后,我继续运行。 LINQ的不重装我的对象,而是重新使用了一个它以前曾在内存! 这是数据并发一个巨大的问题!
你如何禁用的LINQ显然是保持在内存中的对象的这个隐藏的缓存?
编辑 -在反思,这简直不可想象,微软可能会在LINQ的框架已经离开这样一个大裂口。 上面的代码是什么我实际上做了简单化下来的版本,并有可能是我已经错过了一点微妙之处。 总之,我会很感激,如果你会做你自己的试验,以验证以上我的发现是正确的。 另外,必须有某种“秘密开关”,使LINQ的健壮的并发数据更新。 不过什么?
这不是一个问题,我遇到之前(因为我不倾向于保持DataContexts开放的很长一段时间),但它看起来像别人有:
http://www.rocksthoughts.com/blog/archive/2008/01/14/linq-to-sql-caching-gotcha.aspx
LinqToSql有各种各样的工具来处理并发问题。
第一步,然而,承认存在需要解决的并发问题!
首先,DataContext的的预期对象生命周期应该是匹配的UnitOfWork。 如果你持有到一个长时间,你将不得不更加努力地工作,因为该类不是设计用来这种方式。
其次,DataContext的跟踪每个对象的两个副本。 一个是原始状态,一种是改变/多变的状态。 如果你问为ID = 1的MyClass的,它将给你,也给你最后一次,这是改变/多变的版本......不是原来相同的实例 。 它必须这样做是为了防止与内存实例...... LinqToSql不允许一个的DataContext要注意MyClass的两个版本的多变(ID = 1)的并发问题。
第三,DataContext的不知道你的内存是否改变而来的数据库更改之前或之后,所以没有一些指导,不能裁判并发冲突。 它所看到的是:
- 我从数据库中读取MyClass的(ID = 1)。
- 程序员改性MyClass的(ID = 1)。
- 我给MyClass的(ID = 1)回数据库(看这个SQL查看乐观并发在where子句中)
- 如果数据库的版本的原始(乐观并发)相匹配的更新会成功。
- 该更新将失败并发异常,如果数据库的版本不匹配原始。
好了,现在的问题是说,这里有几个方法来对付它。
你可以扔掉的DataContext并重新开始。 这是流传了一段有点重,但至少它很容易实现。
你可以要求原始实例或改变/多变的情况下将通过调用数据库中值刷新DataContext.Refresh(RefreshMode, target)
( 与“备注”一节中许多美好的并发链接参考文档 )。 这将改变客户端,让你的代码工作时的最终结果应该是什么。
您可以在DBML(关闭并发检查ColumnAttribute.UpdateCheck )。 这将禁用乐观并发和您的代码将在踩别人的变化。 同样重手,也容易实现。
在DataContext的ObjectTrackingEnabled属性设置为false。
当ObjectTrackingEnabled设置为true在DataContext的行为就像一个工作单元 。 这将保存在内存中加载的任何对象,以便它可以跟踪更改。 在DataContext需要记住的对象为您最初加载它知道如果任何已经作了修改。
如果您在只读方案的工作,你应该关闭对象跟踪。 它可以是一个不错的性能改进。
如果您没有在只读情况下工作,然后我不知道为什么你希望它以这种方式工作。 如果你做了修改那么为什么你会希望它处于修改状态拉从数据库中?
LINQ to SQL中使用的身份地图设计模式,这意味着它给了主键,它总是会返回一个对象的同一个实例(除非您关闭对象跟踪)。
解决的方法就是要么使用第二个数据背景下,如果你不希望它与一审干扰或如果你刷新的第一个实例。