如何使用LINQ从DataTable中删除行?

19

我有以下代码来从DataTable中删除行:

var rows = dTable.Select("col1 ='ali'");
foreach (var row in rows)
   row.Delete();

上述代码运行正常。如何将此代码转换为LINQ


1
FYI,linq 也会在内部使用循环! - Zaki
1
你为什么喜欢在LINQ中做这件事? - Sriram Sakthivel
@KingKing为什么?'rows'是'DataRow []',有什么阻止你删除的理由吗? - Sriram Sakthivel
1
@SriramSakthivel 我在阅读时没有仔细,实际上 row.Delete() 将修改集合 dTable.Rows 而不是 rows - King King
@KingKing 发生这种事情很正常。 - Sriram Sakthivel
7个回答

42

LINQ并不是用于删除或修改数据的工具,它主要用于查询数据。使用LINQ,您可以选择要删除的数据,然后手动删除这些数据(例如在foreach循环或使用ForEach列表扩展中):

var query = dTable.AsEnumerable().Where(r => r.Field<string>("col1") == "ali");

foreach(var row in query.ToList())
   row.Delete();

更新:使用 LINQ to DataSet,您还可以选择应保留在表中的所有行,并从这些行创建新的 DataTable:

var table = dTable.AsEnumerable()
                  .Where(r => r.Field<string>("col1") != "ali")
                  .CopyToDataTable();

1
错误:集合已被修改;枚举操作可能无法执行。 - Samiey Mehdi
@SamieyMehdi 抱歉,问题已修复。同时添加了替代方案以展示 LINQ 的工作方式——您可以选择要删除的内容,或选择要保留的内容。 - Sergey Berezovskiy
@SamieyMehdi 我非常确定它可以工作。请检查您的代码 - 可能您错过了 ToList() 调用。 - Sergey Berezovskiy
@SamieyMehdi 如果在使用枚举器时修改了表格(或列表),则会抛出“集合已修改”错误,因为数据表枚举器会抛出异常。 (当您尝试在 foreach 中修改列表时也是如此)。 - Sergey Berezovskiy
1
@SamieyMehdi,为什么它不工作?row.Delete()不会修改query.ToList(),所以应该可以工作。 - King King

11
尝试使用扩展方法的内联lambda代码:
  dTable.AsEnumerable().Where(r => r.Field("col1") == "ali").ToList().ForEach(row => row.Delete());
  dTable.AcceptChanges();

1
Mohamed Salemyan 我认为 r.Field("col1") 应该是 r.Field<string>("col1") 这会导致错误。 - Adil
1
是的,阿迪尔。我用<string>写了代码,但有人修改了我的代码并删除了<string>类型。我回滚了编辑,但更改还没有提交。 - Mohamed Salemyan

3

你应该使用for循环或while循环来删除行,而不是foreach循环。

以下是非linq解决方案。

dTable= dTable.Select("col1 <> 'ali'").CopyToDataTable();

LINQ

dTable = dTable.AsEnumerable().Where(r => r.Field<string>("col1") != "ali").CopyToDataTable();

2
那会删除其他所有内容。即使你反转条件,现在你也要复制更多的数据,假设要保留的行比要删除的行多得多。 - Servy
1
@SamieyMehdi你甚至没有注意到Servy的评论吗?如果你的DataTable很大,而你只需要删除一些行,像这样做将会非常低效。 - King King
更不用说这个问题明确要求使用 LINQ 解决,而这个解决方案并没有使用 LINQ(但这比先前提到的低效方法要少一些问题)。 - Servy

0
var results = from row in dTable.Tables["tablename"].AsEnumerable()
          where row.Field<string>("Col1") == "ali" 
          select row;
foreach (DataRow row in results)
{
   dTable.Tables["tablename"].Remove(row);
}

0

试试这个

DataRow[] rows;
rows=dataTable.Select("UserName = 'ABC'"); // UserName is Column Name
foreach(DataRow r in rows)
r.Delete();

0

我进行了广泛的搜索(至少四次谷歌搜索),寻找解决此问题的方法,最终在Sergey Berezovskiy的帖子中发现LINQ不支持删除操作。因此,您可以使用LINQ选择要删除的行,并通过所使用的数据库技术的“通常”机制将它们删除。这似乎使得关于LINQ的数据库无关宣传变得有些愚蠢?

虽然这样做是可行的,但通过更多的实验,您可能能够将两个“For Each”循环减少为一个。

我有一个属性表,我想删除所有具有特定ObjectType(第一个关键字段)和选定属性名称(第三个关键字段)的条目,我想出了以下解决方案。

顺便说一下,REPLY对象有点像错误对象 - 我只是打包错误消息、二进制通过/失败标志和其他一些东西,以便可以从查询中传回大量的信息,并(最终)向用户显示错误。

  ' <summary>
  ' The user has decided they don't want a particular property type so we delete all
  ' properties of that type in the table - belonging to any object of that ObjectType
  ' </summary>
  ' <param name="sObjectType"></param>
  ' <param name="sName"></param>
  ' <returns></returns>
  ' <remarks></remarks>
  Public Function DeleteAllPropsByName(sObjectType As String, sName As String) As Reply

    ' Default answer is 'OK'
    DeleteAllPropsByName = New Reply(True)

    Dim T As DataTable = mDB.DataTableImage(msTableName)
    Dim q = From rw In T.AsEnumerable
            Where rw.Field(Of String)("ObjectType") = sObjectType _
            And rw.Field(Of String)("PropName") = sName

    ' Somewhere to remember our list of target rows to delete
    Dim rows As New List(Of DataRow)

    For Each row In q
      '
      ' LINQ doesn't delete so we need to delete from the Datatable directly.
      ' If we delete here we get the collection modified error so we have to save 
      ' the datarows to ANOTHER list and then delete them from there.
      rows.Add(row)

    Next

    For Each rw As DataRow In rows
      '
      ' Call the Delete routine in my table class passing it the 
      ' primary key of the row to delete
      '
      DeleteAllPropsByName = gDB.Table(msTableName).Delete( _
                                  rw.Item("ObjectType").ToString, _
                                  CInt(rw.Item("ObjectID")), _
                                  rw.Item("PropName").ToString)

      If Not DeleteAllPropsByName.OK Then
        ' The reply object (in DeleteAllPropsByName) has all the error info so we can just
        ' exit and return it if the delete failed.
        Exit Function
      End If

    Next

  End Function

-1
dTable.Rows.Remove(dTable.AsEnumerable().Where(r => r.Field<string>("col1") == "Ali").FirstOrDefault());

1
最好附上解释,以及与OP的字段/值匹配的代码。 - Nathan Tuggy
这将仅从数据表中删除一行。 - Beingnin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接