Почему DataTable.Select () возвращает неправильные строки? - PullRequest
6 голосов
/ 31 марта 2011

Функция 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» правильным синтаксисом для логических столбцов). Но вину можно так же легко поместить на колонку Гуидов. Прежде чем я вернусь к сотням мест, где мы используем 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);

Ответы [ 2 ]

3 голосов
/ 01 апреля 2011

Это определенно ошибка, и похоже, что она существует уже давно. Я нашел эту статью базы знаний , которая описывает точно такую ​​же ошибку в .Net framework 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'")
0 голосов
/ 01 апреля 2011

Не ответ.

Я изменил тест, чтобы ему было легче работать, и нашел более неправильный:

A И B AND ID = '00000000-0000-00000000-0000000000 '

B И A И (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);
    }
}
...