2015-06-23 2 views
0

У меня есть два DataTables: dtChild и dtMaster. enter image description hereНайти совпадение определенных столбцов из первого DataTable во втором

Для каждой строки в dtChild, я хотел бы видеть, если есть совпадение в dtMaster. И это сопоставление основано на конкретных столбцах.

Таким образом, в изображении выше, как DataTables есть столбцы с именами Col2 и COL3. И это интересующие нас столбцы. Во второй строке мы имеем совпадение. Потому что есть строка в dtMaster со значением Col2 равного Value22 и значением Col3 равного Value23.

Я хочу написать запрос LINQ, который возвращает null для первого результата строки (так как нет матча для первого буксире в dtChild) и для второй строки возвращает идентификатор найденной записи в dtMaster (предположим, что dtMaster также имеет столбец первичного ключа с именем Id в этом случае).

N.B. Имена столбцов могут меняться каждый раз, когда мы запускаем программу. Поэтому мы хотим, чтобы наша LINQ была динамичной. Также количество совпадающих столбцов (2 в приведенном выше примере) может варьироваться. Таким образом, может быть случай, когда наше условие основывается на значении 5 столбцов.

+0

Что делать, если имеется несколько совпадений? Вы хотите, чтобы id (я предполагаю 'Col1') только первого совпадения? –

+0

В вашей логике есть что-то очень неправильное: «Для каждой строки в dtChild я хотел бы видеть, есть ли совпадение в dtMaster». Точка отношения «хозяин/ребенок» заключается в том, что строка в главном всегда существует, когда ребенок может существовать или не существовать, а не наоборот –

+0

@TimSchmelter Хороший вопрос. Мы только заботимся о первом матче. Мы хотим, чтобы совпадение возвращалось к значению столбца с именем 'Id', который будет фиксированным, в отличие от других. – Disasterkid

ответ

1

Вы могли бы использовать:

DataTable dtResult = dtChild.Clone(); 
foreach(DataRow row in dtChild.Rows) 
{ 
    DataRow newRow = dtResult.Rows.Add(); 
    newRow.SetField("Col1", row.Field<string>("Col1")); 
    DataRow firstmatchingRow = dtMaster.AsEnumerable() 
     .FirstOrDefault(r => r.Field<string>("Col2") == row.Field<string>("Col2") 
          && r.Field<string>("Col3") == row.Field<string>("Col3")); 
    string col2 = null; 
    string col3 = null; 
    if(firstmatchingRow != null) 
    { 
     col2 = firstmatchingRow.Field<string>("Col2"); 
     col3 = firstmatchingRow.Field<string>("Col3"); 
    } 
    newRow.SetField("Col2", col2); 
    newRow.SetField("Col3", col3); 
} 

Если вы хотите динамический подход, при котором вы можете определить ключевые столбцы обеих таблиц вы могли бы использовать это:

string[] keyColumnNames = { "Col2", "Col3" }; 
DataTable dtResult = dtChild.Clone(); 

DataColumn[] childColumns = dtResult.Columns.Cast<DataColumn>() 
    .Where(c => keyColumnNames.Contains(c.ColumnName)) 
    .ToArray(); 
DataColumn[] masterColumns = dtMaster.Columns.Cast<DataColumn>() 
    .Where(c => keyColumnNames.Contains(c.ColumnName)) 
    .ToArray(); 

foreach (DataRow row in dtChild.Rows) 
{ 
    DataRow newRow = dtResult.Rows.Add(); 
    newRow.SetField("Col1", row.Field<string>("Col1")); 
    var matchingRows = dtMaster.AsEnumerable() 
     .Where(masterRow => !masterColumns.Select(mc => masterRow.Field<string>(mc)) 
      .Except(childColumns.Select(cc => row.Field<string>(cc))) 
      .Any()); 
    DataRow firstMatchingRow = matchingRows.FirstOrDefault(); 
    foreach(DataColumn col in childColumns) 
     newRow.SetField(col, firstMatchingRow == null 
      ? null 
      : firstMatchingRow.Field<string>(col.ColumnName)); 
} 
+0

Имена столбцов могут меняться каждый раз, когда мы запускаем программу. Поэтому мы хотим, чтобы наша LINQ была динамичной. Также количество совпадающих столбцов (2 в приведенном выше примере) может варьироваться. Таким образом, может быть случай, когда наше условие основывается на значении 5 столбцов. – Disasterkid

+1

@Pedram: посмотрите. –

+0

Я попробую второе решение. Вернусь. Благодарю. – Disasterkid

0

Не проверено ...

class Data<T>() 
{ 
    public int Id {get; set;} 
    public T Value{get; set;} 
} 

var cols=dtChild.Columns.OfType<DataColumn>().All(c=>c.Name).toList(); 
var idCol=cols.Single(c=>c=="Id"); 
var valcols=cols.Where(c=>c!="Id"); 

var lst=new List<Data>(); 
var chlds=dtChild.Rows.OfType(DataRow); 
chlds.ToList().ForEach(c=>lst.Add(new Data{ Id=c[idCol], Value=null}); //initialize to null 

foreach(var r1 in chlds) 
{ 
    foreach(var r2 in dtMaster.Rows.OfType(DataRow)) 
    { 
    if (r1[idcol]==r2[idCol]) 
    { 
     forech(var c in valCols) 
     { 
     if (r1[c]==r2[c]) 
     { 
      lst.Single(l=>l.Id==r1[c]).Value= r2[idCol]; 
      break; 
     } 
     } 
    } 
    } 
} 
Смежные вопросы