65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (12投票s)

2009年7月20日

CPOL

5分钟阅读

viewsIcon

95056

downloadIcon

600

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

目录

引言和目标

在本文中,我们将讨论在 LINQ to SQL 中处理并发的一些重要概念。我们首先将了解 LINQ 如何支持乐观并发,然后我们将了解 LINQ 提供了哪些支持来处理并发冲突。接着我们将讨论 LINQ 在字段级别提供的一些微调功能。最后,我们将通过讨论并发冲突发生时的两个重要错误报告选项来结束本文。

请随意下载我的免费 .NET 电子书,其中包含 WCF、WPF、WWF、Silverlight 等 400 个问题和答案。

LINQ 新手? - 一些快速入门

一个好的并发系统应该支持的两件事

一个好的并发系统至少应提供两个重要功能

  • 它应该能够检测是否发生了任何并发冲突。
  • 一旦检测到并发冲突,它应该提供各种方法来处理并发冲突。

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 异常,如下图所示

如果您真的想看到异常,您可以在没有 trycatch 异常块的情况下运行代码。您应该会看到如下图所示的内容。

处理 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 日:首次发布

如需进一步阅读,请观看以下面试准备视频和分步视频系列。

© . All rights reserved.