【问题标题】:How to update a single column in single row in a datatable using LinQ如何使用 LinQ 更新数据表中单行中的单列
【发布时间】:2019-12-18 22:07:13
【问题描述】:

我正在开发一个使用主数据库(数据表)来驱动从 FTP 服务器下载文件的项目。在此过程中,我为主数据库中的每个客户端创建了一个本地数据库(另一个数据表)。这是我用来创建客户端数据库的代码:

Console.WriteLine(" Building Client Database")
Clientdatabase = New DataTable
Clientdatabase = DataBaseTable.Clone
Dim RowList = (From row In DataBaseTable.AsEnumerable() Where (row.Field(Of String)("co") = CompanyID))
For Each RowItem In RowList
    Clientdatabase.ImportRow(RowItem)
Next

此代码按预期工作; Clientdatabase 包含的内容是准确的。我的问题是更新客户端数据库中的一个字段。在一个循环中,我获取了包含 FTP 服务器上目标文件的完整路径和文件名的每条记录,然后我尝试使用本地路径更新客户端数据库,但我无法让它工作。在循环中,这段代码正在执行逻辑并下载文件:

Dim FileList = (From row In DataBaseTable.AsEnumerable().Select(Function(x) New With {
     Key .co = x.Field(Of String)("co"),
     Key .path = x.Field(Of String)("path"),
     Key .OriginalFileName = x.Field(Of String)("OriginalFileName"),
     Key .DocumentID = x.Field(Of String)("DocumentID")
               }).Where(Function(s) s.co = CompanyID).ToList)
Console.Write(" Downloading Files : ")
Dim CursorArray() As String = Split("\,|,/,-", ",")
Dim FileCounter As Integer = 1
For Each CompanyFile In FileList
    Dim ThisFile As String = CompanyFile.path.Replace("\", "/")
    Dim Results As TransferOperationResult = DownloadFromPath(ThisFile, DestinPath)
    Dim TmpParts() As String = Split(ThisFile, "/")
    Dim LocalName As String = TmpParts(UBound(TmpParts))
    If Results.IsSuccess Then
        UpdateCDBPath(CompanyID, CompanyFile.DocumentID, LocalName)
        ReportData &= CompanyID & ",Success," & CompanyFile.OriginalFileName & "," & ThisFile & vbCrLf
    Else
        ReportData &= CompanyID & ",Failed," & CompanyFile.OriginalFileName & "," & ThisFile & vbCrLf
    End If
    FileCounter += 1
    Console.Write(CursorArray(FileCounter Mod 4) & Chr(8))
Next

更新调用(UpdateCDBPath)包含以下代码:

Sub UpdateCDBPath(ByVal CompanyID As String, ByVal DocumentID As String, TargetValue As String)
    Dim result = (From row In Clientdatabase.AsEnumerable().Select(Function(x) New With {
                    Key .DocumentID = x.Field(Of String)("DocumentID"),
                    Key .Co = x.Field(Of String)("co")
                }).Where(Function(s) s.DocumentID = DocumentID And s.Co = CompanyID ) Select Clientdatabase)
    For Each ItemRow In result
        ItemRow.Rows(0).Item("Path") = TargetValue
    Next
End Sub

问题出在此代码块内。 DocumentID 是客户端内唯一标识文档的唯一 GUID,TargetValue 是替换路径(文件的本地路径)。如果我正确理解了 Linq(但我不是),它应该只返回我感兴趣的行 (1),因此我是如何设置新路径的。我已经从各种示例中尝试了无数示例,但无法使其工作。当我检查客户端数据库时,没有更新任何路径字段。我还确认在本地保存客户端数据库后,字段仍然相同。有人可以指出我正确的方向,告诉我哪里出了问题或其他什么,以便我解决这个问题。我最终需要更新客户端数据库中的其他字段;这是第一个。提前感谢您提供的所有帮助!

【问题讨论】:

  • 看起来s.Co = DocumentID 应该是s.Co = CompanyID
  • 我已经读到 LINQ(语言无关 Query)是用于查询数据的。为什么要强制它执行非查询?
  • @玛丽。客户端数据表很大,每一行都需要单独更新。因此,我尝试使用 where 子句在流程进行时更新每一行。我不知道高级行号以使用更直接的方法,我所看到的所有内容都使用 dt.rows(#) 语法。循环通过每一行会很慢。我可以使用其他方法吗?
  • @ItsPete 感谢您指出这一点。我已经编辑了源代码(和这篇文章)并再次测试(几次);结果变量返回整个客户端数据表,而不仅仅是有问题的。
  • 我发现在大表中,使用 sqlquery 可能会快得多。使用 Linq,您必须遍历所有记录。您可以使用常规 sql 命令来更快地执行此操作。查看docs.microsoft.com/en-us/ef/ef6/querying/…

标签: vb.net linq datatable


【解决方案1】:

result 的 linq 返回一个 EnumerableRowCollection(Of System.Data.DataTable),这意味着它包含整个 Clientdatabase 的行列表。

由于每一行都包含整个DataRowCollectionItemRow.Rows(0).Item("Path") = TargetValue 将只更新Clientdatabase 中的第一行,其次数与results 中的记录一样多。

将查询更改为返回EnumerableRowCollection(Of System.Data.DataRow) 允许在循环中直接访问每一行:

Sub UpdateCDBPath(ByVal CompanyID As String, ByVal DocumentID As String, TargetValue As String)
    Dim result = From row In Clientdatabase.AsEnumerable()
                 Where row.Field(Of String)("DocumentID") = DocumentID AndAlso
                       row.Field(Of String)("co") = CompanyID
                 Select row

    For Each ItemRow In result
        ItemRow.Item("Path") = TargetValue
    Next
End Sub

【讨论】:

  • 太棒了!像我期望的那样工作,一个 Linq 更新。就像一个注释:有一个额外的 ) 作为结果 def 行的末尾。非常感谢你。只需对例程进行少量更改,它就可以更新结果集中的任何列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-19
  • 2015-12-20
相关资源
最近更新 更多