关于是用LINQ to SQL模拟并发冲突的问题

光脚丫思考 2010-09-17 03:52:36
LINQ to SQL的Skip()和Take()运算符都是采用延迟加载的方式执行的。我在测试并发冲突的时候,试着使用这两个运算符来获取若干记录。因为需要模拟出两个用户的并发修改操作,所以使用了两个自定义数据上下文。就是通过Skip()和Take()这两个运算符来获取测试数据的。但是,因为这两个运算符是延迟加载的,所以当一个用户更新了数据之后,另一个用户实际上是在前一个用户更新后才去读取数据库的。这样一来肯定不会产生并发冲突的了。请问有没有什么办法让Skip()和Take()禁用延迟加载呢?下面是测试代码:

// 用户A和用户B同时获取相同的记录。
var UserACustomers = dbUserA.Customers.Skip(23).Take(7);
var UserBCustomers = dbUserB.Customers.Skip(23).Take(7);

// 用户B首先修改数据并更新到数据。
foreach (var CustomerObject in UserBCustomers)
{
CustomerObject.ContactName = "UserB";
CustomerObject.ContactTitle = "UserB";
CustomerObject.Country = "UserB";
CustomerObject.City = "UserB";
CustomerObject.Address = "UserB";
}
dbUserB.SubmitChanges();

// 然后才是用户A修改数据,并尝试更新到数据库,此时将引发并发冲突。
foreach (var CustomerObject in UserACustomers)
{
CustomerObject.ContactName = "UserA";
CustomerObject.ContactTitle = "UserA";
CustomerObject.Country = "UserA";
CustomerObject.City = "UserA";
CustomerObject.Address = "UserA";
}
dbUserA.SubmitChanges(ConflictMode.FailOnFirstConflict);

...全文
214 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
NeptuneGrass 2010-10-03
  • 打赏
  • 举报
回复
LINQ很复杂啊
光脚丫思考 2010-10-03
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 neptunegrass 的回复:]
LINQ很复杂啊
[/Quote]
LINQ是个大话题,不过我这个话题却仅局限于LINQ to SQL,所以仍然是个小话题,不复杂的。
光脚丫思考 2010-09-19
  • 打赏
  • 举报
回复
再次感谢各位网友的热心帮助!今个该结贴了!^_^
光脚丫思考 2010-09-17
  • 打赏
  • 举报
回复
十分的感谢各位的关注和热心帮助!现在可以正确的模拟出并发冲突了。我把整个测试代码贴上来吧!^_^这个测试的目的是确定ConflictMode枚举的使用,也就是指定引发并发冲突的时间。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data.Linq;

namespace Demo03Ex01
{
class Program
{
static void Main(string[] args)
{
NorthwindDataContext dbUserA = new NorthwindDataContext(@"C:\LINQ\Northwind.mdf");
NorthwindDataContext dbUserB = new NorthwindDataContext(@"C:\LINQ\Northwind.mdf");

StreamWriter UserAWriter = File.CreateText(@"C:\LINQ\UserA.log");
dbUserA.Log = UserAWriter;

StreamWriter UserBWriter = File.CreateText(@"C:\LINQ\UserB.log");
dbUserB.Log = UserBWriter;

try
{
// 用户A和用户B同时获取相同的记录。
var UserACustomers = dbUserA.Customers.Skip(30).Take(7).ToList();
var UserBCustomers = dbUserB.Customers.Skip(30).Take(7).ToList();

// 用户B首先修改数据并更新到数据。
foreach (var CustomerObject in UserBCustomers)
{
CustomerObject.ContactName = "UserB";
CustomerObject.ContactTitle = "UserB";
CustomerObject.Country = "UserB";
CustomerObject.City = "UserB";
CustomerObject.Address = "UserB";
}
dbUserB.SubmitChanges();

// 然后才是用户A修改数据,并尝试更新到数据库,此时将引发并发冲突。
foreach (var CustomerObject in UserACustomers)
{
CustomerObject.ContactName = "UserA";
CustomerObject.ContactTitle = "UserA";
CustomerObject.Country = "UserA";
CustomerObject.City = "UserA";
CustomerObject.Address = "UserA";
}
dbUserA.SubmitChanges(ConflictMode.FailOnFirstConflict);
}
catch (ChangeConflictException ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine();
Console.WriteLine("Change Conflict Objects Count : {0}",
dbUserA.ChangeConflicts.Count);
}

UserAWriter.Close();
UserBWriter.Close();
}
}
}
光脚丫思考 2010-09-17
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 foren_whb 的回复:]
这其实是跟linq的工作原理相关的,
不一定是延迟加载造成的。
linq 语句执行的时候得到其实是SQL语句,
只有到最后要使用结果的时候,
才真正执行该SQL语句,
所以,
你的结果跟你的测试方法也是有关系的。
[/Quote]
其实,当我遇到这个问题的时候,我就想到要设置这个属性来解决的。可是当看到智能提示上关于这个属性的注释,我就放弃这种尝试了。
注释内容是这样的:Specifies whether to delay-load one-to-many or one-to-one relationships.
我在想,这个属性所谓的延迟加载应该是针对LINQ to SQL的映射关系而言的。而我的这个测试代码中很明显是没有包含这种关系的。
另外,从属性的名字来看,此属性的意思是延迟加载,而我们讨论的却是延迟执行的问题。貌似这两者有着小小的区别。
比如说,声明性查询语法肯定是延迟执行了,通常情况下是在foreach语句的时候它才执行。而一些扩展方法,比如这里的Take()和Skip()同样是延迟执行的。而我之前使用的First()运算符就是立即执行的。
丰云 2010-09-17
  • 打赏
  • 举报
回复
这其实是跟linq的工作原理相关的,
不一定是延迟加载造成的。
linq 语句执行的时候得到其实是SQL语句,
只有到最后要使用结果的时候,
才真正执行该SQL语句,
所以,
你的结果跟你的测试方法也是有关系的。
光脚丫思考 2010-09-17
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 foren_whb 的回复:]
有很多扩展方法会导致立即加载,如ToList、ToDictionary、ToLookup、ToArray等,
通过这种方式可以避免修改整个DataContext的DeferredLoadingEnabled属性
[/Quote]
呵呵,我试用了一下ToList这个方法,还真就测试成功了。以前我以为经过ToList这个方法转换后,实体类将不再受数据上下文的跟踪,没想到,经过这个测试才发现,这些实体类对象继续受数据上下文的跟踪!哎!疏忽呀……
光脚丫思考 2010-09-17
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 foren_whb 的回复:]
设置DataContext的DeferredLoadingEnabled属性为false,显示的关闭默认的延迟加载方式
[/Quote]
我之前也尝试过使用这种方式,但是似乎并没有关闭延迟加载。同样是使用上面的测试代码,而且将两个自定义数据上下文的DeferredLoadingEnabled都设置为false。此时,在第二个foreach语句块中获取的客户信息是前一个foreach语句块中修改过的数值。这岂不是表示仍然采用了延迟加载的方式在用户B修改完毕数据后才读取数据库的数据吗?
苏州牛恋歌 2010-09-17
  • 打赏
  • 举报
回复
关注一下
丰云 2010-09-17
  • 打赏
  • 举报
回复
有很多扩展方法会导致立即加载,如ToList、ToDictionary、ToLookup、ToArray等,
通过这种方式可以避免修改整个DataContext的DeferredLoadingEnabled属性
PxxxP 2010-09-17
  • 打赏
  • 举报
回复
放入缓存中
丰云 2010-09-17
  • 打赏
  • 举报
回复
设置DataContext的DeferredLoadingEnabled属性为false,显示的关闭默认的延迟加载方式

8,497

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 LINQ
社区管理员
  • LINQ
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧