Использует ли LINQ DataRelations для оптимизации объединений?

Я нигде не могу найти ответ на этот вопрос, и, прежде чем начать копаться в сгенерированном коде с помощью Reflector, я подумал, что стоит спросить:

Предположим, у меня есть следующий запрос LINQ, выполняемый для DataTables в DataSet:

var list = 
   from pr in parentTable.AsEnumerable()
   join cr in childTable.AsEnumerable() on cr.Field<int>("ParentID") equals pr.Field<int>("ID")
   where pr.Field<string>("Value") == "foo"
   select cr;

Если между родительской таблицей и дочерней таблицей существует связь DataRelation, которая использует показанные ключевые поля, будет ли LINQ использовать ее? То есть найдет ли он строки в родительской таблице, для которых Значение равно «foo», а затем вызовет GetChildRows для проецирования дочерних строк?

Или это то, что я должен указать явно? (И если да, то как мне это сделать?)

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
0
2 320
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Это объяснение: http://msdn.microsoft.com/en-us/library/bb386969.aspx

Но в приведенном выше примере вы сообщаете linq о родительско-дочерних отношениях с синтаксисом «JOIN». Я бы порекомендовал вам создать строго типизированный набор данных, если это возможно, и все связи и соединения будут обрабатываться за вас.

Ответ принят как подходящий

Я так не думаю. В этом случае LINQ to Objects, вероятно, просто будет рассматривать обе стороны как обычные перечисляемые объекты и выполнять соединение вручную (не глядя на DataRelation).

Копание в Reflector, похоже, не дало никаких указаний на то, что LINQ использует DataRelations, но этот код ужасно трудно читать. Итак, я написал небольшой тест производительности, и если в тесте, который я пропустил, есть что-то глупое, результаты будут довольно окончательными: нет, LINQ не использует DataRelations и GetChildRows () для проецирования объединенных строк. Если вы хотите перебирать дочерние строки, вы должны сформулировать запрос LINQ для явного вызова GetChildRows (). И ни один из подходов не так эффективен, как написание кода, который выполняет итерацию по массиву, возвращаемому GetChildRows ().

Отчасти прискорбно, потому что разница в производительности для больших наборов данных достаточно значительна, поэтому замена LINQ явно реализованным кодом часто оказывается целесообразной, что обычно не относится к LINQ.

Мой тестовый код ниже. Время итерации LINQ с использованием соединения остается неизменным (около 580–590 мс на моем компьютере) независимо от того, создается ли DataRelation до или после него. Итерация LINQ, использующая GetChildRows (), занимает около 280 мс,

Итерация непосредственно через GetChildRows () занимает менее миллисекунды. Это довольно удивительно для меня - достаточно, чтобы я предположил, что у меня есть ошибка в коде, когда я впервые запускал тест. (Вот почему я записываю счет каждый раз - чтобы убедиться, что циклы не были оптимизированы компилятором.)

class Program
{
    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();
        DataSet ds = new DataSet();
        DataTable t1 = new DataTable();
        t1.Columns.Add(new DataColumn
                           {
                               ColumnName = "ID",
                               DataType = typeof (int),
                               AutoIncrement = true
                           });
        t1.PrimaryKey = new [] { t1.Columns["ID"]};
        ds.Tables.Add(t1);

        DataTable t2 = new DataTable();
        t2.Columns.Add(new DataColumn
        {
            ColumnName = "ID",
            DataType = typeof(int),
            AutoIncrement = true
        });
        t2.Columns.Add("ParentID", typeof(int));
        t2.PrimaryKey = new[] { t2.Columns["ID"] };
        ds.Tables.Add(t2);

        sw.Reset();
        sw.Start();
        PopulateTables(t1, t2);
        sw.Stop();
        Console.WriteLine("Populating tables took {0} ms.", sw.ElapsedMilliseconds);
        Console.WriteLine();

        var list1 = from r1 in t1.AsEnumerable()
                   join r2 in t2.AsEnumerable()
                       on r1.Field<int>("ID") equals r2.Field<int>("ParentID")
                   where r1.Field<int>("ID") == 1
                   select r2;

        sw.Reset();
        sw.Start();
        int count = 0;
        foreach (DataRow r in list1)
        {
            count += r.Field<int>("ID");
        }
        sw.Stop();
        Console.WriteLine("count = {0}.", count);
        Console.WriteLine("Completed LINQ iteration in {0} ms.", sw.ElapsedMilliseconds);
        Console.WriteLine();

        sw.Reset();
        sw.Start();
        ds.Relations.Add(new DataRelation("FK_t2_t1", t1.Columns["ID"], t2.Columns["ParentID"]));
        sw.Stop();
        Console.WriteLine("Creating DataRelation took {0} ms.", sw.ElapsedMilliseconds);

        sw.Reset();
        sw.Start();
        var list2 =
            from r1 in t1.AsEnumerable()
            from r2 in r1.GetChildRows("FK_t2_t1")
            where r1.Field<int>("ID") == 1
            select r2;

        count = 0;
        foreach (DataRow r in list2)
        {
            count += r.Field<int>("ID");
        }
        sw.Stop();
        Console.WriteLine("count = {0}.", count);
        Console.WriteLine("Completed LINQ iteration using nested query in {0} ms.", sw.ElapsedMilliseconds);
        Console.WriteLine();

        sw.Reset();
        sw.Start();
        DataRow parentRow = t1.Select("ID = 1")[0];
        count = 0;
        foreach (DataRow r in parentRow.GetChildRows("FK_t2_t1"))
        {
            count += r.Field<int>("ID");
        }
        sw.Stop();
        Console.WriteLine("count = {0}.", count);
        Console.WriteLine("Completed explicit iteration of child rows in {0} ms.", sw.ElapsedMilliseconds);
        Console.WriteLine();

        Console.ReadLine();
    }

    private static void PopulateTables(DataTable t1, DataTable t2)
    {
        for (int count1 = 0; count1 < 1000; count1++)
        {
            DataRow r1 = t1.NewRow();
            t1.Rows.Add(r1);
            for (int count2 = 0; count2 < 1000; count2++)
            {
                DataRow r2 = t2.NewRow();
                r2["ParentID"] = r1["ID"];
                t2.Rows.Add(r2);
            }
        }
    }
} 

Что ж, вы всегда можете написать свою собственную реализацию LINQ, которая делает this - это не так много работы, как кажется (Джон попытался сделать это за 1 час на демонстрации и получил большую часть пути).

Marc Gravell 24.12.2008 00:31

О, это опасное искушение.

Robert Rossney 24.12.2008 03:14

Другие вопросы по теме