Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Linq缓存数据值-主要并发问题?_C#_Linq_Linq To Sql_Concurrency - Fatal编程技术网

C# Linq缓存数据值-主要并发问题?

C# Linq缓存数据值-主要并发问题?,c#,linq,linq-to-sql,concurrency,C#,Linq,Linq To Sql,Concurrency,下面是我做的一个小实验: 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 = dataCon

下面是我做的一个小实验:

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
MyClass obj=dataContext.GetTable().Where(x=>x.ID=1.Single();
Console.WriteLine(obj.MyProperty);//输出=“初始”
Console.WriteLine(“等待…”);//在这行后面放一个断点
obj=null;
obj=dataContext.GetTable()。其中(x=>x.ID=1)。Single();//与之前相同,但已重新加载
Console.WriteLine(obj.MyProperty);//输出仍然=“初始”
obj.MyOtherProperty=“foo”;
dataContext.SubmitChanges();//引发并发异常
当我到达第3行之后的断点时,我转到一个SQL查询窗口,并手动将该值更改为“updated”。然后我继续跑。Linq不会重新加载我的对象,但会重新使用它以前在内存中的对象!这对于数据并发来说是一个巨大的问题

如何禁用Linq显然保存在内存中的对象的隐藏缓存


编辑-反省一下,微软在Linq框架中留下如此巨大的鸿沟是完全不可想象的。上面的代码是我实际正在做的事情的简化版本,可能有一些细微之处我遗漏了。简言之,如果你能亲自做实验来验证我的上述发现是否正确,我将不胜感激。或者,必须有某种“秘密开关”,使Linq对并发数据更新具有鲁棒性。但是什么呢?

这不是我以前遇到过的问题(因为我不想让DataContext长时间处于打开状态),但看起来其他人已经:


将DataContext的ObjectTrackinEnabled属性设置为false

当ObjectTrackingEnabled设置为true时,DataContext的行为类似于。它会将任何对象加载到内存中,以便跟踪对它的更改。DataContext必须在最初加载对象时记住该对象,以了解是否进行了任何更改

如果在只读场景中工作,则应关闭对象跟踪。这可能是一个不错的性能改进


如果您不是在只读场景中工作,那么我不确定您为什么希望它以这种方式工作。如果您已经进行了编辑,那么为什么要将其从数据库中拉入修改状态

linqtosql使用身份映射设计模式,这意味着它将始终为给定的主键返回对象的相同实例(除非关闭对象跟踪)


解决方案是,如果不希望第二个数据上下文干扰第一个实例,则使用第二个数据上下文;如果需要,则刷新第一个实例。

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()中关闭并发检查。这将禁用乐观并发,您的代码将践踏其他任何人的更改。也很重,也很容易实现。

更糟糕的是,如果您按照他的建议在那里设置ObjectTrackingEnabled=false,则只能从数据库中读取;你不能做提交更改!这真的让生活很艰难!这里有一个指向C#gotcha KB:Ye的链接,但我不是在只读环境中工作。还有其他想法吗?这是设计的。它是为您设计的,可以使用optamistic并发性拉入状态、修改和写回。您可以在DataContext上调用Refresh,但这可能会终止您所做的任何更改。它不是为了提供实时同步。实时同步和编辑不能很好地结合在一起。