【问题标题】:Why is LINQ query to DataTable not working?为什么对 DataTable 的 LINQ 查询不起作用?
【发布时间】:2013-03-11 02:17:00
【问题描述】:

我有一个数据表 dt,它包含以下内容:

如您所见,这里有两组文件:基线(第 1-3 列)和目标(第 4-6 列)。所以在这种情况下,我有 4 个基线文件 m4、m5、m1 和 m3(第 5 行中的 m1 是从第 3 行复制的)和一个目标文件 m1。问题是基线文件 m1.txt 的信息是重复的,所以我尝试使用以下 LINQ 语句将其删除:

var extraneousRows = dt.Rows.Cast<DataRow>().
    Where(
        row => row["BASELINE_FOLDER"] == baselineSubfolder
        && row["BASELINE_FILE"] == baselineFilename
        && row["BASELINE_CHECKSUM"] == baselineChecksum
        && row["STATUS"] == "remove"
    ).ToArray();

foreach (DataRow dr in extraneousRows)
    {
        dt.Rows.Remove(dr);
    }

这应该从 DataTable 中删除第三行,但它没有。如果我省略 &amp;&amp; row["STATUS"] == "remove" 行,代码可以正常工作,所以我知道它是有效的。而且baselineSubfolder、baselineFilename 和baselineChecksum 的值是正确的,所以这不是问题所在。

但由于某种原因,当我包含关于状态列的那一行时,它不会检测到该行在 DataTable 中,即使它显然是根据 DataSet Visualizer(上图)。所以它永远不会进入 foreach 循环,也不会删除必要的文件。为什么???

我可能应该提到基线文件信息(前 4 行)是从数据库中检索的,而目标文件字段是根据用户输入生成的。不过,我看不出信息的来源有什么关系,因为我是直接查询 DataTable ...

更新

好的,在遵循 idipous 和 Jamie Keeling 的建议后,我确​​定问题与从未填充过的 foreach 循环有关。因为这个查询应该只返回一行,所以我完全消除了循环。我修改后的代码如下所示:

var extraneousRows = dt.Rows.Cast<DataRow>().
    Where(
        row => row["BASELINE_FOLDER"] == baselineSubfolder
        && row["BASELINE_FILE"] == baselineFilename
        && row["BASELINE_CHECKSUM"] == baselineChecksum
        && row["STATUS"] == "remove"
    ).SingleOrDefault();

dt.Rows.Remove(extraneousRows);

无论出于何种原因,extraneousRows 保持为空,并且最后一行正在生成运行时错误:IndexOutOfRangeException: The given DataRow is not in the current DataRowCollection

为什么这不起作用?

【问题讨论】:

  • 图片中的状态是remove not remove。不知道是不是这个。
  • 调试时可以断点查询并检查 lambda 的所有组件。
  • 您是否检查过“extraneousRows”是否有要迭代的元素?
  • 使用 SingleOrDefault() 代替 toArray();
  • 不不,你根本不使用 foreach。你只有一个数据行 dt.Rows.Remove(extraneousRows);

标签: linq c#-4.0 datatable


【解决方案1】:

事实证明,问题在于我需要将列值转换为字符串。解决方案非常简单:只需在列名和中提琴后添加一个 .ToString() !下面的代码就像一个魅力:

var extraneousRows = dt.Rows.Cast<DataRow>().
    Where(
        row => row["BASELINE_FOLDER"].ToString() == baselineSubfolder
        && row["BASELINE_FILE"].ToString() == baselineFilename
        && row["BASELINE_CHECKSUM"].ToString() == baselineChecksum
        && row["STATUS"].ToString() == "remove"
    ).SingleOrDefault();

dt.Rows.Remove(extraneousRows);

我还找到了一种非 LINQ 方法,即遍历 DataTable 的所有行。这不是最有效的,但它确实有效:

for (int z = 0; z < dt.Rows.Count; z++)
{
    if ((dt.Rows[z]["BASELINE_FOLDER"].ToString() == baselineSubfolder)
        && (dt.Rows[z]["BASELINE_FILE"].ToString() == baselineFilename)
        && (dt.Rows[z]["BASELINE_CHECKSUM"].ToString() == baselineChecksum)
        && (dt.Rows[z]["STATUS"].ToString() == "remove"))
    {
        dt.Rows[z].Delete();
    }
}
dt.AcceptChanges();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2012-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多