如何在 LINQ to SQL 中处理并发?






4.60/5 (12投票s)
如何在 LINQ to SQL 中处理并发?
目录
- 引言和目标
- LINQ 新手? - 一些快速入门
- 一个好的并发系统应该支持的两件事
- LINQ 默认支持乐观并发
- 让我们看看乐观并发是否真的有效
- LINQ 中处理并发冲突的三种方法
- 字段级别并发的微调
- 并发冲突时的错误报告选项
- 历史
引言和目标
在本文中,我们将讨论在 LINQ to SQL 中处理并发的一些重要概念。我们首先将了解 LINQ 如何支持乐观并发,然后我们将了解 LINQ 提供了哪些支持来处理并发冲突。接着我们将讨论 LINQ 在字段级别提供的一些微调功能。最后,我们将通过讨论并发冲突发生时的两个重要错误报告选项来结束本文。
请随意下载我的免费 .NET 电子书,其中包含 WCF、WPF、WWF、Silverlight 等 400 个问题和答案。
LINQ 新手? - 一些快速入门
- 你是一个完全的新手吗?- LINQNewbie.aspx
- 想使用 LINQ 定义 1 对多和多对 1 吗?- OneManyandOneOneLINQ.aspx
- 本文处理了多次往返的问题 - OptimizingLINQ.aspx
- 不知道如何使用 LINQ 调用存储过程?- 6stepsLINQ.aspx
一个好的并发系统应该支持的两件事
一个好的并发系统至少应提供两个重要功能
- 它应该能够检测是否发生了任何并发冲突。
- 一旦检测到并发冲突,它应该提供各种方法来处理并发冲突。
LINQ 默认支持乐观并发
LINQ 实体构成了 LINQ 引擎的核心。所有数据库数据都通过 datacontext
获取并提供给 LINQ 对象。一旦数据被获取到 LINQ 对象中,LINQ 对象就会与数据库断开连接。换句话说,LINQ 是一种断开连接的体系结构。由于断开连接的体系结构,我们唯一可以支持的锁定类型是乐观锁定。
好消息!!!LINQ 默认支持乐观并发。
让我们看看乐观并发是否真的有效
让我们做一个小的示例测试,看看 LINQ 是否真的默认支持乐观并发。所以我们将执行以下操作
- 我们将打开一个数据上下文,获取一条记录并修改该记录。我们不会调用
SubmitChanges
,换句话说,我们不会对物理数据库进行最终更新。 - 然后我们将打开一个新的
DataContext
连接,获取相同的记录并在数据库中物理更新该记录。 - 然后我们将回到同一条旧记录,使用
SubmitChanges
调用物理更新。通过这种方式,我们将能够模拟并发冲突。
下面是代码。
我们首先获取记录并更改客户名称,但我们尚未调用物理数据库提交。
DataContext objContext = new DataContext(strConnectionString);
clsCustomer objCustomer = objContext.GetTable<clsCustomer>().First<clsCustomer>();
objCustomer.CustomerName = "Iwanttochange";
然后我们调用一个不同的方法来更改此记录,从而模拟并发冲突。
SomeOneChangedData();
SomeOneChangedData
方法是一个简单的代码,它获取相同的记录并进行更改。
private void SomeOneChangedData()
{
DataContext objContext = new DataContext(strConnectionString);
clsCustomer objCustomer = objContext.GetTable<clsCustomer>().First<clsCustomer>();
// changing to some random customer name
objCustomer.CustomerName = new Random().NextDouble().ToString();
objContext.SubmitChanges();
}
然后我们回到旧的 DataContext
对象并尝试调用 SubmitChanges
方法。此调用将创建并发冲突,因为 SomeOneChangedData
方法已经更改了数据。
objContext.SubmitChanges();
如果您处于调试模式,您应该会看到抛出 ChangeConflictException
异常,如下图所示
如果您真的想看到异常,您可以在没有 try
和 catch
异常块的情况下运行代码。您应该会看到如下图所示的内容。
处理 LINQ 中并发冲突的三种方法
当我们开始本文时,我们讨论了每个好的并发系统都应该具备的两个重要功能。我们已经看到了第一个功能的实时演示,它展示了 LINQ 如何帮助检测并发冲突。现在让我们看看 LINQ 如何满足并发的第二个功能,即处理并发冲突。
LINQ 提供了三种处理并发冲突的方法。要处理并发冲突,我们需要将 LINQ to SQL 代码包装在 TRY
块中并捕获 ChangeConflictException
。然后我们可以遍历 ChangeConflicts
集合来指定我们希望如何解决冲突。
catch (ChangeConflictException ex)
{
foreach (ObjectChangeConflict objchangeconf in objContext.ChangeConflicts)
{
objchangeconf.Resolve(RefreshMode.OverwriteCurrentValues);
}
}
LINQ 系统提供了 3 种处理并发冲突的方法
KeepCurrentValues
:当指定此选项并发生并发冲突时,LINQ 保持调用 LINQ 实体对象的值不变,并且不会将数据库中的新值推送到 LINQ 对象中。OverwriteCurrentValues
:当指定此选项时,当前 LINQ 对象数据将替换为数据库值。KeepChanges
:这是最奇怪的选项,但在某些情况下可能会有所帮助。当我们谈论类时,它可以有许多属性。因此,已更改的属性保持不变,而未更改的属性则从数据库中获取并替换。
我们需要使用 RefereshMode
来指定我们需要哪些选项,如以下代码片段所示。
字段级别并发的微调
LINQ 并发系统提供的最佳选项之一是控制字段级别的并发行为。我们可以使用 UpdateCheck
属性指定三个选项
Never
:检查并发冲突时不要使用此字段。Always
:此选项指定始终使用此字段检查并发冲突。WhenChanged
:仅当成员值已更改时,才使用此字段检测并发冲突。
下面是代码片段,它展示了我们如何使用 UpdateCheck
属性来控制属性/字段级别的并发选项,如上所述。
[Column(DbType = "nvarchar(50)",UpdateCheck=UpdateCheck.Never)]
public string CustomerCode
{
set
{
_CustomerCode = value;
}
get
{
return _CustomerCode;
}
}
并发冲突时的错误报告选项
LINQ 并发系统允许您指定希望如何报告冲突。LINQ 系统提供了两种报告冲突的方式
ContinueOnConflict
:此选项告诉 LINQ 引擎即使存在冲突也要继续,并在过程结束时返回所有冲突。FailOnFirstConflict
:此选项表示一旦发生第一个冲突就停止,并立即返回所有冲突。换句话说,LINQ 引擎不会继续执行代码。
这两个选项都可以作为 ConflictMode enum
的输入提供给 SubmitChanges
方法。下面是指定冲突模式的代码片段
objContext.SubmitChanges(ConflictMode.ContinueOnConflict);
历史
- 2009 年 7 月 20 日:首次发布
如需进一步阅读,请观看以下面试准备视频和分步视频系列。