【问题标题】:Linq updates extra rowsLinq 更新额外的行
【发布时间】:2017-10-11 20:35:57
【问题描述】:

我正在使用 vb.net 实体来访问 sql server 2014 数据库中的数据。

我有一个接收“所有者”对象的函数,如果所有者在表中有多个当前条目,它应该更新旧条目以具有以前的状态。

Private Shared Sub CreatePreviousOwners(currentOwners As List(Of Owner), prop As compProp)
Dim names = prop.GetVendorsNames()
Using context = New GovernContext()
            Dim sameOwners = From v In currentOwners
                             Where names.Any(Function(o) o.Na_Id = v.Na_Id)
                             Select v
           If sameOwners.Count > 0 Then
                For Each owner In sameOwners
                    'Find all entries prior to the newest
                    Dim prevOwner = From p In context.Owner
                                    Where p.Status = "O" _
                                    And owner.Na_Id = p.Na_Id _
                                    And p.P_Id = prop.p_id _
                                    And p.As_Of_Date < owner.As_Of_Date 
                                    Select p
                    'Update all found entries to previous
                    For Each own As Owner In prevOwner
                        own.Status = "P"
                    Next
                Next
                context.SaveChanges()
            End If
        End Using
    End Sub

这是一个小数据集:

p_id    na_id   AS_OF_DATE              status
596     589494  2008-09-10 00:00:00.000 O
596     589494  2017-08-02 00:00:00.000 O
596     1453364 2017-08-02 00:00:00.000 P

当我单步执行代码时,prevOwner 序列中只有一个条目。

当我运行 sql profiler 查看 linq 查询时,更新语句缺少任何 as_of_date 条件。 以下是分析器的查询:

exec sp_executesql N'UPDATE [dbo].[Owner]
SET [Status] = @0
WHERE (([P_Id] = @1) AND ([Na_Id] = @2))
',N'@0 nvarchar(max) ,@1 int,@2 int',@0=N'P',@1=596,@2=589494

是我的 sql 格式错误,还是我遗漏了什么?

【问题讨论】:

  • 您期望什么状态变化以及为什么?
  • 你 100% 确定 owner.as_of_data 不是什么东西吗?
  • @TToni 如果已售出房产,则会在所有者表中创建一条状态设置为“O”的新记录。我在这里期望的唯一状态变化是顶行的状态设置为“P”。相反,两个“O”状态都设置为“P”
  • @Rolan - 那么您如何期望 Linq 和 SQL 唯一标识一行?你为什么抱怨AS_OF_DATE 丢失了,因为你没有将它定义为你的密钥的一部分。
  • @Rohan,不确定你在这里想说什么。我希望我解释得足够清楚,您的问题出在哪里: as_of_date 不是您的密钥的一部分,因此它不会在数据库查询中使用。

标签: sql-server vb.net linq


【解决方案1】:

您似乎对 Entity Framework 期望过高。当 EF 更新数据库记录时,它总是一次只有一条记录。它不做批量更新。

以下是您的代码中发生的情况(我稍作修改):

Private Shared Sub CreatePreviousOwners(currentOwners As List(Of Owner), prop As compProp)
    Dim names = prop.GetVendorsNames()
    Using context = New GovernContext()

        'Runs a SQL SELECT query and creates a list of owners
        Dim sameOwners = (From v In currentOwners
                         Where names.Any(Function(o) o.Na_Id = v.Na_Id)
                         Select v).ToList()

        For Each owner In sameOwners
            'Find all entries prior to the newest

            'Runs another SQL SELECT query
            Dim prevOwner = From p In context.Owner
                            Where p.Status = "O" _
                            And owner.Na_Id = p.Na_Id _
                            And p.P_Id = prop.p_id _
                            And p.As_Of_Date < owner.As_Of_Date 
                            Select p
            'Update all found entries to previous

            'Executes the SELECT query and loops through the results
            For Each own As Owner In prevOwner

                'Adds a modified entry to EF's change tracker
                own.Status = "P"

            Next
        Next

        'Runs update statements for each modified entry in the change tracker
        context.SaveChanges()

    End Using
End Sub

如您所见,当 EF 准备好更新数据库时,它不知道如何收集修改后的条目。更新可以更智能地完成,即在更新满足条件 p.As_Of_Date &lt; owner.As_Of_Date 的批次 Owners 的语句中,但收集数据和更新它们是 EF 中完全独立的操作。

这就是为什么您只能看到其中一条记录由其主键标识的 UPDATE 语句。您可能会看到 许多 个。

有支持批量(或批量)更新、插入和删除的第三方库。

【讨论】:

  • 感谢您澄清 Gert。在 Alex 和您自己指出之前,我没有意识到 EF 使用主键来运行更新语句。我将不得不阅读一本关于 EF 架构的书(有什么建议吗?),这样我就不会期望从中得到错误的东西。再次感谢!
猜你喜欢
  • 2016-02-18
  • 1970-01-01
  • 1970-01-01
  • 2014-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-16
相关资源
最近更新 更多