LINQ to SQL: несколько соединений для нескольких столбцов. Это возможно?


131

Дано:

Таблица TABLE_1со следующими столбцами:

  • ID
  • ColumnA
  • ColumnB
  • ColumnC

У меня есть SQL запрос , где TABLE_1присоединяется на себя дважды основаны от ColumnA, ColumnB, ColumnC. Запрос может выглядеть примерно так:

Select t1.ID, t2.ID, t3.ID
  From TABLE_1 t1
  Left Join TABLE_1 t2 On
       t1.ColumnA = t2.ColumnA
   And t1.ColumnB = t2.ColumnB
   And t1.ColumnC = t2.ColumnC
  Left Join TABLE_1 t3 On
       t2.ColumnA = t3.ColumnA
   And t2.ColumnB = t3.ColumnB
   And t2.ColumnC = t3.ColumnC
... and query continues on etc.

Проблема:

Мне нужно, чтобы этот запрос был переписан в LINQ. Я пробовал нанести удар:

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on t1.ColumnA equals t2.ColumnA
      && t1.ColumnB equals t2.ColumnA
    // ... and at this point intellisense is making it very obvious
    // I am doing something wrong :(

Как мне написать свой запрос в LINQ? Что я делаю не так?

Ответы:


244

Объединение нескольких столбцов в Linq to SQL немного отличается.

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on new { t1.ColumnA, t1.ColumnB } equals new { t2.ColumnA, t2.ColumnB }
    ...

Вы должны воспользоваться преимуществами анонимных типов и составить тип для нескольких столбцов, с которыми вы хотите сравнить.

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

ИЗМЕНИТЬ Пример добавления второго соединения на основе комментария.

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on new { A = t1.ColumnA, B = t1.ColumnB } equals new { A = t2.ColumnA, B = t2.ColumnB }
    join t3 in myTABLE1List
      on new { A = t2.ColumnA, B =  t2.ColumnB } equals new { A = t3.ColumnA, B = t3.ColumnB }
    ...

4
это отлично работает для двух соединений. Он мне нужен для работы с ТРЕМЯ объединениями. Извините, второй блок кода немного вводил в заблуждение.
Аарона

46
Если вы получаете ошибку компилятора при выводе типа, проверьте две вещи: (1) совпадают ли типы и (2) совпадают ли имена столбцов. Часть имен - это ошибка. Этот пример не будет компилироваться, даже если все столбцы - varchars join T2 in db.tbl2 on new { T1.firstName, T1.secondName } equals new { T2.colFirst, T2.colSecond }. Если вы измените его на это, он скомпилируется,join T2 in db.tbl2 on new { N1 = T1.firstName, N2 = T1.secondName } equals new { N1 = T2.colFirst, N2 = T2.colSecond }
user2023861 03

4
Проблема с именованием может быть устранена путем соединения t1 в myTABLE1List с t2 в myTABLE1List на новом {colA = t1.ColumnA, colB = t1.ColumnB}, равном новому {colA = t2.ColumnA, colBBt2.ColumnB}
Бакер Накви,

1
позвольте мне отредактировать пример, так как он требует присвоения анонимным свойствам
AceMark

1
Что-то здесь не так .. с LINQ. Я могу присоединиться к нескольким таблицам, я могу присоединиться к нескольким полям ... однако я не могу сделать это для обоих, как показывает пример здесь. Скажем, у вас есть только соединение на 1 поле ... и у вас есть второе соединение после него. Если вы измените первое соединение (или оба), чтобы просто использовать new {x.field} равняется new {y.field}, возникает ошибка компилятора. Функционально вы ничего не меняли. Использование .Net 4.6.1.
user2415376

12

В LINQ2SQL вам редко требуется явное соединение при использовании внутренних соединений.

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

родительско-дочерние отношения

Затем вы можете просто получить доступ к связанным таблицам с "точечной нотацией"

var q = from child in context.Childs
        where child.Parent.col2 == 4
        select new
        {
            childCol1 = child.col1,
            parentCol1 = child.Parent.col1,
        };

сгенерирует запрос

SELECT [t0].[col1] AS [childCol1], [t1].[col1] AS [parentCol1]
FROM [dbo].[Child] AS [t0]
INNER JOIN [dbo].[Parent] AS [t1] ON ([t1].[col1] = [t0].[col1]) AND ([t1].[col2] = [t0].[col2])
WHERE [t1].[col2] = @p0
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [4]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1

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

Изменить
Это, конечно, применимо только тогда, когда вы хотите присоединиться к нашей модели базы данных. Если вы хотите присоединиться к «вне модели» вам необходимо обратиться к руководству включается как в ответ от Quintin Robinson


11

Title_Authors - это поиск двух вещей, которые объединяют результаты проекта и продолжают связывание

        DataClasses1DataContext db = new DataClasses1DataContext();
        var queryresults = from a in db.Authors                                          
                    join ba in db.Title_Authors                           
                    on a.Au_ID equals ba.Au_ID into idAuthor
                    from c in idAuthor
                    join t in db.Titles  
                    on c.ISBN equals t.ISBN 
                    select new { Author = a.Author1,Title= t.Title1 };

        foreach (var item in queryresults)
        {
            MessageBox.Show(item.Author);
            MessageBox.Show(item.Title);
            return;
        }

10

Вы также можете использовать:

var query =
    from t1 in myTABLE1List 
    join t2 in myTABLE1List
      on new { ColA=t1.ColumnA, ColB=t1.ColumnB } equals new { ColA=t2.ColumnA, ColB=t2.ColumnB }
    join t3 in myTABLE1List
      on new {ColC=t2.ColumnA, ColD=t2.ColumnB } equals new { ColC=t3.ColumnA, ColD=t3.ColumnB }

3
AHHH !! Это работает! И КЛЮЧЕВАЯ РАЗНИЦА в том, что вам нужно сделать часть «ColA =», чтобы в другом соединении было то же поле. В течение многих лет я этого не делал, но мне также нужно было всего одно соединение в нескольких полях. Но теперь мне нужно больше, и он РАБОТАЕТ ТОЛЬКО, если я назначу имя переменной полям, как в этом примере.
user2415376

3

Я хотел бы привести еще один пример, в котором используется несколько (3) объединений.

 DataClasses1DataContext ctx = new DataClasses1DataContext();

        var Owners = ctx.OwnerMasters;
        var Category = ctx.CategoryMasters;
        var Status = ctx.StatusMasters;
        var Tasks = ctx.TaskMasters;

        var xyz = from t in Tasks
                  join c in Category
                  on t.TaskCategory equals c.CategoryID
                  join s in Status
                  on t.TaskStatus equals s.StatusID
                  join o in Owners
                  on t.TaskOwner equals o.OwnerID
                  select new
                  {
                      t.TaskID,
                      t.TaskShortDescription,
                      c.CategoryName,
                      s.StatusName,
                      o.OwnerName
                  };

9
Не одно и то же - речь идет об объединении таблиц на основе нескольких столбцов в каждой, а не объединении нескольких таблиц на основе одного столбца в каждой.
Изохронный

1

Вы также можете присоединиться, если количество столбцов в обеих таблицах не одинаковое, и можете сопоставить статическое значение столбцу таблицы.

from t1 in Table1 
join t2 in Table2 
on new {X = t1.Column1, Y = 0 } on new {X = t2.Column1, Y = t2.Column2 }
select new {t1, t2}

-6

На мой взгляд, это самый простой способ объединить две таблицы с несколькими полями:

from a in Table1 join b in Table2    
       on (a.Field1.ToString() + "&" + a.Field2.ToString())     
       equals  (b.Field1.ToString() + "&" + b.Field2.ToString())  
     select a

В SQL это будет значительно медленнее, чем соединение по каждому столбцу отдельно (хотя все равно будет довольно быстро, если набор данных небольшой). Предположительно linq сгенерирует очевидный SQL, поэтому помните о производительности, если вы используете это решение.
EGP

-10

Вы можете написать свой запрос вот так.

var query = from t1 in myTABLE1List // List<TABLE_1>
            join t2 in myTABLE1List
               on t1.ColumnA equals t2.ColumnA
               and t1.ColumnB equals t2.ColumnA

Если вы хотите сравнить свой столбец с несколькими столбцами.


1
@ user658720 Добро пожаловать в StackOverFlow :). Я бы посоветовал вам отформатировать код, чтобы его было легче читать. Вы можете выделить текст и нажать кнопку кода в редакторе.
Аарона
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.