2015-07-20 4 views
1

Я пытаюсь объединить две таблицы данных с использованием Linq на основе нескольких критериев. Я смог получить слияние, используя этот пост: Combining two tables into one. Однако этот пример соединяется только с одним первичным ключом, и мне нужно указать несколько критериев.Внешнее объединение двух таблиц данных по нескольким критериям

DataTable1 (table1 в коде)

+-----------------------------------------------+ 
| CLIENT,USER_NAME,LAST_LOGIN_DT_TM,BIRTH_DT_TM | 
+-----------------------------------------------+ 
| CLIENT1, USER1, 30-2014, 5-5-1980    | 
| CLIENT1, USER2, 12-21-2014, 5-2-1990   | 
| CLIENT2, USER3, 11-30-2014, 5-1-1950   | 
| CLIENT2, USER4, 12-15-2014, 1-1-1900   | 
+-----------------------------------------------+ 

DataTable 2 (table2 в коде)

+-------------------------------+ 
| CLIENT,USER_NAME,TOTAL_ORDERS | 
+-------------------------------+ 
| CLIENT1, USER1, 1500   | 
| CLIENT2, USER2, 2500   | 
+-------------------------------+ 

Я хочу, чтобы выход выглядеть следующим образом:

+-------------------------------------------------------------+ 
| CLIENT,USER_NAME,LAST_LOGIN_DT_TM,BIRTH_DT_TM, TOTAL_ORDERS | 
+-------------------------------------------------------------+ 
| CLIENT1, USER1, 1-30-2014, 5-5-1980, 1500     | 
| CLIENT1, USER2, 12-21-2014, 5-2-1990,      | 
| CLIENT2, USER2, 11-30-2014, 5-1-1950, 2500     | 
| CLIENT2, USER1, 12-15-2014, 1-1-1900,      | 
+-------------------------------------------------------------+ 

Вот что До сих пор:

DataTable targetTable = table1.Clone(); 

var dt2Columns = table2.Columns 
         .OfType<DataColumn>() 
         .Select(dc => new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping)); 
var dt2FinalColumns = from dc in dt2Columns.AsEnumerable() 
         where targetTable.Columns.Contains(dc.ColumnName) == false 
         select dc; 
         targetTable.Columns.AddRange(dt2FinalColumns.ToArray()); 

// This only matches on USER_NAME now, how do I add in CLIENT? 
var rowData = from row1 in table1.AsEnumerable() 
       join row2 in table2.AsEnumerable() 
       on row1.Field<string>("USER_NAME") equals row2.Field<string>("USER_NAME") 
       select row1; 
// This gives me the matched rows in rowData, but I'm not sure how to join it with original table1 

ответ

4

Чтобы присоединиться на несколько столбцов, вы должны использовать анонимные типы:

from row1 in table1.AsEnumerable() 
join row2 in table2.AsEnumerable() on 
    new { userName = row1.Field<string>("USER_NAME"), client = row1.Field<string>("CLIENT") } 
equals 
    new { userName = row2.Field<string>("USER_NAME"), client = row2.Field<string>("CLIENT") } 
select new { 
    userName = row1.Field<string>("USER_NAME"), 
    client = row1.Field<string>("CLIENT"), 
    totalOrders = row2.Field<int>("TOTAL_ORDERS"), 
    (...) 
} 
+0

Это заботится о согласовании и помещает две сопоставленные строки в rowData. Каков наилучший способ после этого добраться до моего желаемого выхода внешнего соединения? – colinwurtz

+0

Вы можете проецировать другой анонимный тип. Обновлен мой ответ. – MarcinJuraszek

+0

Что делать, если я не знаю всех столбцов в каждом DataTable до времени выполнения? В моем сценарии реального мира таблица1 содержит около 55 столбцов, а таблица2 имеет 25 или около того. Все, что я знаю, это то, что каждая таблица имеет столбцы «КЛИЕНТ» и «USER_NAME». – colinwurtz

0

FielYou нужно зарегистрироваться с помощью анонимного типа с использованием новых {Field1, Field2}

IEnumerable<DataRow> rowData = from row1 in table1.AsEnumerable() 
      join row2 in table2.AsEnumerable() 
      on new { col1 = row1.Field<string>("USER_NAME"), col2 = row1.Field<string>("SecondField") } equals {col1 = row2.Field<string>("USER_NAME") , col2 = row2.Field<string>("SecondField") } 
      select row1; 
+0

Не компилируется. Это не правильное объявление анонимного типа, потому что компилятор не сможет вывести имена свойств для вас. – MarcinJuraszek