Как сделать объединение в LINQ для нескольких полей в одном объединении - PullRequest
227 голосов
/ 17 декабря 2008

Мне нужно выполнить запрос LINQ2DataSet, который объединяет несколько полей (как

var result = from x in entity
join y in entity2 
       on x.field1 = y.field1 
and 
          x.field2 = y.field2

Я еще не нашел подходящего решения (я могу добавить дополнительные ограничения к предложению where, но это далеко от подходящего решения, или использовать это решение, но оно предполагает эквиджоин).

Возможно ли в LINQ объединить несколько полей в одно соединение?

EDIT

var result = from x in entity
             join y in entity2
             on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

- это решение, на которое я ссылался как на приведенное выше эквиджоин.

Далее РЕДАКТИРОВАТЬ

Чтобы ответить на критику, согласно которой мой первоначальный пример был эквиджоин, я признаю, что мое текущее требование касается эквихоина, и я уже использовал решение, на которое я ссылался выше.

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

Спасибо, как всегда, за все предложения и комментарии

Ответы [ 12 ]

122 голосов
/ 17 декабря 2008
var result = from x in entity
   join y in entity2 on new { x.field1, x.field2 } equals new { y.field1, y.field2 }
85 голосов
/ 17 декабря 2008

Решение с анонимным типом должно работать нормально. LINQ может представлять только эквиджоины (в любом случае, с предложениями соединения), и, действительно, это то, что, как вы сказали, вы хотите выразить в любом случае на основе вашего исходного запроса.

Если вам не нравится версия с анонимным типом по какой-то конкретной причине, вы должны объяснить эту причину.

Если вы хотите сделать что-то кроме того, о чем вы изначально просили, приведите пример того, что вы действительно хотите сделать.

РЕДАКТИРОВАТЬ: Отвечая на редактирование в вопросе: да, чтобы сделать объединение «диапазон дат», вам нужно вместо этого использовать предложение where. Они на самом деле семантически эквивалентны, так что это просто вопрос доступных оптимизаций. Equijoins обеспечивают простую оптимизацию (в LINQ to Objects, которая включает в себя LINQ to DataSets) путем создания поиска на основе внутренней последовательности - его можно рассматривать как хеш-таблицу от ключа до последовательности записей, соответствующих этому ключу.

Делать это с диапазонами дат несколько сложнее. Однако, в зависимости от того, что именно вы подразумеваете под «объединением диапазона дат», вы можете сделать что-то подобное - если вы планируете создавать «полосы» дат (например, по одной в год), чтобы две записи, которые происходят в одном и том же году (но не в одну и ту же дату), должны совпадать, тогда вы можете сделать это, просто используя эту полосу в качестве ключа. Если это сложнее, например одна сторона объединения обеспечивает диапазон, а другая сторона объединения предоставляет одну дату, соответствующую, если она попадает в этот диапазон, которая будет лучше обрабатываться с предложением where (после второго предложения from) IMO , Вы могли бы сделать что-то особенное в стиле фанк, заказав одну или другую сторону для более эффективного поиска совпадений, но это было бы большой работой - я бы сделал такую ​​вещь только после проверки, является ли производительность проблемой.

68 голосов
/ 14 октября 2014
var result = from x in entity1
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }

Это необходимо сделать, если имена столбцов различаются в двух сущностях.

46 голосов
/ 04 марта 2014

Просто чтобы завершить это с помощью эквивалентного синтаксиса цепочки методов:

entity.Join(entity2, x => new {x.Field1, x.Field2},
                     y => new {y.Field1, y.Field2}, (x, y) => x);

В то время как последний аргумент (x, y) => x - это то, что вы выбираете (в приведенном выше случае мы выбираем x).

29 голосов
/ 09 декабря 2015

Я думаю, что более удобочитаемым и гибким вариантом является использование функции Where:

var result = from x in entity1
             from y in entity2
                 .Where(y => y.field1 == x.field1 && y.field2 == x.field2)

Это также позволяет легко перейти от внутреннего соединения к левому, добавив .DefaultIfEmpty ().

9 голосов
/ 22 августа 2014
var result = from x in entity
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }
             select new 
             {
               /// Columns
              };
8 голосов
/ 17 декабря 2008

вы могли бы сделать что-то вроде (ниже)

var query = from p in context.T1

        join q in context.T2

        on

        new { p.Col1, p.Col2 }

        equals

         new { q.Col1, q.Col2 }

        select new {p...., q......};
7 голосов
/ 17 декабря 2008

Используя оператор соединения, вы можете выполнять только эквайоины. Другие типы объединений могут быть созданы с использованием других операторов. Я не уверен, будет ли проще использовать именно эти методы для точного соединения, которое вы пытаетесь сделать, или изменив предложение where. Документацию по предложению соединения можно найти здесь . В MSDN есть статья об операциях объединения с несколькими ссылками на примеры других объединений.

2 голосов
/ 16 апреля 2018

Как полная цепочка методов, которая будет выглядеть следующим образом:

lista.SelectMany(a => listb.Where(xi => b.Id == a.Id && b.Total != a.Total),
                (a, b) => new ResultItem
                {
                    Id = a.Id,
                    ATotal = a.Total,
                    BTotal = b.Total
                }).ToList();
2 голосов
/ 02 декабря 2014

Если имена полей отличаются в сущностях

var result = from x in entity
   join y in entity2 on 
          new {
                field1=   x.field1,
               field2 =  x.field2 
             } 
          equals
         new { 
                field1= y.field1,
                field2=  y.myfield
              }
select new {x,y});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...