【问题标题】:Why does DataTable.Select() return the wrong rows?为什么 DataTable.Select() 返回错误的行?
【发布时间】:2011-03-31 18:01:44
【问题描述】:

DataTable.Select() 函数使用这样的过滤器返回错误的行...

“booleanColumn1 AND booleanColumn2 AND GuidColumn1 = '00000000-0000-0000-0000-000000000000')”

对此格式进行几乎任何更改都会修复它(参见示例)。在 dataView 上使用相同的过滤器可以正常工作。我很想把它改成

“booleanColumn1 = 1 AND booleanColumn2 = 1 AND GuidColumn1 = '00000000-0000-0000-0000-000000000000')”

并声明它已修复(文档没有提及“A”或“A = 1”是否是布尔列的正确语法)。但责任也很容易归咎于 Guid 专栏。在我重新访问我们在代码库中使用 DataTable.Select() 的数百个地方之前,我希望看看是否有人知道真正发生了什么。

DataTable dt = new DataTable("dt");
dt.Columns.AddRange(new DataColumn[]
{
  new DataColumn("ID", typeof(Guid)),
  new DataColumn("A", typeof(bool)),
  new DataColumn("B", typeof(bool))
});

dt.Rows.Add(Guid.Empty, false, true);

// this incorrectly returns a row
Debug.WriteLine(dt.Select("B AND A AND ID = '00000000-0000-0000-0000-000000000000'").Length);

// yet it's fine for a DataView (correctly returns 0 rows)
DataView dv = new DataView(dt);
dv.RowFilter = "B AND A AND ID = '00000000-0000-0000-0000-000000000000'";
Debug.WriteLine(dv.Count);

// these correctly return 0 rows
Debug.WriteLine(dt.Select("B AND A").Length);
Debug.WriteLine(dt.Select("B AND A AND CONVERT(ID, 'System.String') = '00000000-0000-0000-0000-000000000000'").Length);
Debug.WriteLine(dt.Select("A AND B AND ID = '00000000-0000-0000-0000-000000000000'").Length);
Debug.WriteLine(dt.Select("B = 1 AND A AND ID = '00000000-0000-0000-0000-000000000000'").Length);
Debug.WriteLine(dt.Select("ID = '00000000-0000-0000-0000-000000000000' AND B AND A").Length);
Debug.WriteLine(dt.Select("B AND (A AND ID = '00000000-0000-0000-0000-000000000000')").Length);

// still wrong
Debug.WriteLine(dt.Select("B AND A AND ID = '00000000-0000-0000-0000-000000000000'").Length);

【问题讨论】:

  • 这个问题的一个有趣特性是,如果您重新排列 DataTable 中的列,查询会返回不同的结果。我尝试将 ID 列从 DataTable 中的第一列移动到第三列,并且第一个 Select() 没有返回任何行,正如预期的那样。

标签: .net select datatable dataview rowfilter


【解决方案1】:

这绝对是一个错误,而且它看起来已经存在很长时间了。我发现 this knowledgebase article 描述了 .Net 框架 1.1 中完全相同的错误。

似乎完全忽略了第二个条件,因为我发现以下变体也返回一行:

dt.Select("B AND false AND ID = '00000000-0000-0000-0000-000000000000'")
dt.Select("B AND 0 AND ID = '00000000-0000-0000-0000-000000000000'")

然而,这正确返回 0 行:

dt.Select("B AND A AND A AND ID = '00000000-0000-0000-0000-000000000000'")

【讨论】:

    【解决方案2】:

    没有答案。

    我修改了测试以使其更易于使用,但发现更多错误:

    A AND B AND ID = '00000000-0000-0000-0000-000000000000'

    B AND A AND(ID = '0000000-0000-0000-0000-000000000000')

    这对我来说似乎是一个错误。您可能希望将其带到 Microsoft Connnect。

    using System;
    using System.Data;
    using System.Diagnostics;
    
    class Program
    {
        static void Main(string[] args)
        {
            DataTable dt = new DataTable("dt")
            {
                Columns =
                {
                  new DataColumn("ID", typeof(Guid)),
                  new DataColumn("A", typeof(bool)),
                  new DataColumn("B", typeof(bool)),
                }
            };
    
            dt.Rows.Add(Guid.Empty, false, false);
            dt.Rows.Add(Guid.Empty, false, true);
            dt.Rows.Add(Guid.Empty, true, false);
            dt.Rows.Add(Guid.Empty, true, true);
    
            Console.BackgroundColor = ConsoleColor.Black;
            Console.Clear();
            Console.ForegroundColor = ConsoleColor.Green;
            foreach (DataRow row in dt.Rows)
                Console.WriteLine("ID = {0}, A = {1}, B = {2}", row["ID"], row["A"], row["B"]);
            Console.WriteLine();
    
            // this incorrectly returns a row
            Test(dt, "B AND A AND ID = '00000000-0000-0000-0000-000000000000'");
    
            // these correctly return 0 rows
            Test(dt, "B AND A");
            Test(dt, "B AND A AND CONVERT(ID, 'System.String') = '00000000-0000-0000-0000-000000000000'");
            Test(dt, "A AND B AND ID = '00000000-0000-0000-0000-000000000000'");
            Test(dt, "B = 1 AND A AND ID = '00000000-0000-0000-0000-000000000000'");
            Test(dt, "ID = '00000000-0000-0000-0000-000000000000' AND B AND A");
            Test(dt, "B AND (A AND ID = '00000000-0000-0000-0000-000000000000')");
            Test(dt, "(B AND A AND ID = '00000000-0000-0000-0000-000000000000')");
    
            // still wrong
            Test(dt, "B AND A AND ID = '00000000-0000-0000-0000-000000000000'");
    
            // also incorrect for both A = True and B = True
            Test(dt, "B AND A AND (ID = '0000000-0000-0000-0000-000000000000')");
    
            if (Debugger.IsAttached)
            {
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.WriteLine();
                Console.WriteLine("Press any key to continue . . . ");
                Console.ReadKey();
            }
    
            Console.ResetColor();
            Console.Clear();
        }
    
        public static void Test(DataTable dt, string filter)
        {
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine(filter);
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("    DT = {0}, DV = {1}",
                dt.Select(filter).Length,
                new DataView { Table = dt, RowFilter = filter }.Count);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-19
      • 1970-01-01
      • 2014-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      相关资源
      最近更新 更多