【问题标题】:LINQ to SQL - Determining if I have stale dataLINQ to SQL - 确定我是否有过时的数据
【发布时间】:2010-08-03 21:16:15
【问题描述】:

我通过 LINQ to SQL 从数据库中提取计划数据,因此使用 DataContext 对象。数据定义了何时应该执行某些操作,并且可以独立于我的服务进行更新。

我会定期轮询数据库以查看计划是否已更新并相应地调整我的计划。

也就是说,如果我知道如何确定数据是否过时,我会这样做。

  • 是否需要在每次检查时创建一个新的 DataContext
  • 是否需要为 Row 类型实现自定义相等方法并遍历表?

理想情况下,我会使用相同的数据上下文进行另一个选择并获取对表的引用,然后调用 Equals。我意识到我生活在梦想的土地上。

【问题讨论】:

  • Dream Land 怎么样?...我一直在考虑搬到那里。

标签: c# linq-to-sql


【解决方案1】:

好问题!

我在这个问题上找到了这篇博客文章,有人想将 SqlDependency 与 LINQ to SQL 一起使用......

http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2007/05/04/9302.aspx

这将与 this 一起用于 WinForms。 (您没有指定 WinForms 或 ASP.NET)

编辑 - 添加

请注意,这仅适用于客户端数量非常少的客户端应用程序(WinForms 等),或者使用 ASP.NET 应用程序。 MSDN 文档在http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency.aspx 的文档中说明了这一点:

SqlDependency 被设计为使用 在 ASP.NET 或中间层服务中 相对较小的地方 具有依赖关系的服务器数量 主动针对数据库。它是 不是为在客户端使用而设计的 应用程序,其中数百或 成千上万的客户端计算机将 设置 SqlDependency 对象 单个数据库服务器。

但是,如果您正在设计一个只有少数用户的应用,这应该是可以接受的。

【讨论】:

【解决方案2】:

派生自 DataContext 的自动生成的类并非长期存在的对象。在绝大多数用例中,您应该实例化一个,读取所需的数据和/或进行所需的更改,提交,然后忘记对象。它并不直接表示与数据库的连接——实例化大量 DataContexts 并不一定会打开与数据库的多个连接。

这样做的结果是您应该认为您的数据总是过时,尤其是在单独的进程可以访问同一个数据库的情况下。一旦您检索到数据,其他进程就可以立即更新该数据。确保不陈旧的唯一方法是维护一个打开的事务,而且我相信你知道,保持事务打开时间过长的后果是其他进程会找到数据库高度无响应,就好像它非常慢 - 所以只使用一个事务处理一个几乎只涉及需要原子的数据库访问的处理步骤。

因此,在您的具体情况下,找出是否有任何新操作要执行的唯一方法是不断询问数据库。您不必一直检索数据并使用 Equals 进行比较;你可以只检索你还没有得到的所有数据,即告诉数据库只返回 new 行。因为我不知道你的数据库架构,所以我在这里编造一些东西,但我相信这会给你一个想法:

var newActions = db.ScheduledActions.Where(act => !oldActions.Contains(act)).ToList();
if (newActions.Any()) {
    // ... do something intelligent with the new actions ...
    oldActions = oldActions.Concat(newActions);
    // or perhaps oldActions.AddRange(newActions); if oldActions is a List<>
}

编辑:我现在意识到您不仅需要检查操作,还需要检查现有操作的更改。就我个人而言,我实现这一点的方式是在 ScheduledActions 表上设置一个日期/时间字段,该字段指定最后一次更改的时间。然后,您不需要自定义相等比较器,而是可以使用它来找出发生了什么变化。不幸的是,这意味着您需要检索所有操作,即使是那些没有更改的操作。在以下示例中,我假设 ScheduledActions 由 string 类型的主键标识;如果您使用数字键,请将其更改为 int

Dictionary<string, ScheduledAction> oldActions = new ...;

[...]

var allActions = db.Actions.ToList();
var changedActions = allActions.Where(act => !oldActions.ContainsKey(act.Id) || oldActions[act.Id].LastChanged < act.LastChanged).ToList();
if (changedActions.Any())
{
    // do something intelligent here
}

【讨论】:

  • 你这里的 db 对象是什么类型的?
【解决方案3】:

我有另一个答案,这与我的第一个不同,但我仍然认为第一个在有限的情况下是一个有效的选项,所以我单独发布。

您真正谈论的是使用 LINQ 处理并发问题。 Microsoft 在此处提供了相关指导:

http://msdn.microsoft.com/en-us/library/bb399373.aspx

【讨论】:

    【解决方案4】:

    首先,您需要非常清楚地定义哪些数据(表、列)确切地受您的更改/更新监视以及更改该数据时数据库端究竟发生了什么。在您的情况下,“计划已更新”是什么意思 - 单行中的一列更改但不影响优先级或影响优先级更改的列?影响调度的数据和只影响处理的数据是否有明确的区分。

    即使在原则上,对这些问题的回答也至关重要地决定了什么是可行的。一般来说,调度问题没有抽象的解决方案。

    一旦您确定了什么是什么以及什么会影响什么,并将实际调度的数据(确定何时处理某事)与处理日期(确定某事的处理方式)分开,您就会将问题减少到只有两个变化点和两个反应点。

    然后您可以使用存储过程和触发器在数据库端控制插入和更新,以便所有新事物都被标记为这样。然后你创建一个只查询市场行并将它们标记为“已读”的存储过程。当您的中间层收到它们时,它会调用另一个 sproc 进行确认,并且该 sproc 会将它们标记为旧的。其变化取决于实际架构,但这是关键 - 当场标记和更新数据状态 - 在 SQL 中的含义。如果没有及时确认(这意味着您的中间层已死),SQL 还需要一个触发器来将记录从“已读”恢复为“新”。

    与 DC 的 LINQ 完全不同。 一旦您解决了这个问题,您确实可以执行相当于单个查询的操作,并且只接收相对于先前读数的新项目。

    此外,您从 LINQ 收到的不是对任何形式的表格的引用 - 它是收到的记录的表示 - 只有当您的查询没有拼出您的字段时,它们才会看起来像表格记录实际需要。当您开始使用 sporcs 时,它将表示 sproc 的结果集是什么——可以是 5 个表的连接,但总共只能选择 3 个字段。

    【讨论】:

      猜你喜欢
      • 2013-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多