Создайте объединил DataTable от двух DataTables, к которым присоединяются с LINQ. C#

У меня есть следующий код, который заполняется dataTable1 и dataTable2 с двумя простыми SQL-запросами, dataTableSqlJoined заполнено от тех же таблиц, но объединился.

Я пытаюсь записать запрос LINQ, который может создать dataTableLinqJoined как будто это было создано с помощью SQL. В моем примере ниже, это только возвращает значения из dataTable1.

Проблема, которую я имею, состоит в том, что вставить SELECT из запроса linq. Как я могу создать новый DataRow, содержащий все Столбцы от обоих DataRows. Я не буду знать точных имен столбцов / схема запросов до времени выполнения.

sqlCommand = new SqlCommand("SELECT ID, A, B FROM Table1", sqlConnection, sqlTransaction);
sqlAdapter = new SqlDataAdapter(sqlCommand);
DataTable dataTable1 = new DataTable();
sqlAdapter.Fill(dataTable1);

sqlCommand = new SqlCommand("SELECT ID, C, D FROM Table2", sqlConnection, sqlTransaction);
sqlAdapter = new SqlDataAdapter(sqlCommand);
DataTable dataTable2 = new DataTable();
sqlAdapter.Fill(dataTable2);

sqlCommand = new SqlCommand("SELECT Table1.ID, A, B, Table2.ID, C, D FROM Table1 INNER JOIN Table2 ON Table1.ID = Table2.ID", sqlConnection, sqlTransaction);
sqlAdapter = new SqlDataAdapter(sqlCommand);
DataTable dataTableSqlJoined = new DataTable();
sqlAdapter.Fill(dataTableSqlJoined);

var dataRows =
    from
        dataRows1 in dataTable1.AsEnumerable()
    join
        dataRows2 in dataTable2.AsEnumerable()
    on
        dataRows1.Field<int>("ID") equals dataRows2.Field<int>("ID")
    select
        dataRows1; // + dataRows2;

DataTable dataTableLinqJoined = dataRows.CopyToDataTable();

Некоторое время больше фона, объединенный запрос является очень интенсивным DB и вызывает проблемы производительности. Данные, возвращенные первым запросом, довольно статичны и могут в большой степени кэшироваться. Данные, возвращенные вторым запросом постоянно, изменяются, но быстры для выполнения и поэтому не должны кэшироваться. Существует также много кода, уверенного после передачи объединенного DataTable и поэтому нет многих выполнимых опций, доступных мимоходом данные в другом формате.

22
задан Robin Day 4 March 2010 в 13:56
поделиться

3 ответа

Вы уже просматривали эту страницу?

КАК: Реализовать вспомогательный класс DataSet JOIN в Visual C # .NET

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

DataTable targetTable = dataTable1.Clone();
var dt2Columns = dataTable2.Columns.OfType<DataColumn>().Select(dc => 
    new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping));
targetTable.Columns.AddRange(dt2Columns.ToArray());
var rowData =
    from row1 in dataTable1.AsEnumerable()
    join row2 in dataTable2.AsEnumerable()
        on row1.Field<int>("ID") equals row2.Field<int>("ID")
    select row1.ItemArray.Concat(row2.ItemArray).ToArray();
foreach (object[] values in rowData)
    targetTable.Rows.Add(values);

Я думаю, что это настолько кратко, насколько вы сможете это сделать, и я объясню почему: это схема.

DataRow не является независимым объектом; он зависит от того, владеет ли он DataTable , и не может жить без него. Не существует поддерживаемого способа для создания «отключенного» DataRow ; метод расширения CopyToDataTable () работает со строками, которые уже существуют в одном DataTable , и просто копирует схему из источника (помните, что каждый DataRow имеет ссылку на его родительская Таблица ) перед копированием самих строк (скорее всего, с помощью ImportRow , хотя я на самом деле не открывал Reflector для проверки).

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

Затем вы, наконец, можете создавать строки - но только по одной, поскольку DataTable и связанный с ним DataRowCollection не предоставляют никаких методов для добавления нескольких строк за раз. .Вы, конечно, можете добавить свой собственный метод расширения для DataRowCollection , чтобы сделать этот "вид" лучше:

public static void AddRange(this DataRowCollection rc,
    IEnumerable<object[]> tuples)
{
    foreach (object[] data in tuples)
        rc.Add(tuples);
}

Затем вы можете избавиться от foreach в первом методе и замените его на:

targetTable.Rows.AddRange(rowData);

Хотя на самом деле это просто смещение многословия, а не его устранение.

В итоге, пока вы работаете с устаревшей иерархией классов DataSet , всегда будет немного беспорядка. Расширения Linq to DataSet хороши, но они всего лишь расширения и не могут изменить указанные выше ограничения.

20
ответ дан 29 November 2019 в 05:29
поделиться

Извините, если я покажусь вам идиотом.

Я думаю, у вас должна быть готова финальная таблица (со всеми полями таблицы A и таблицы B).
И, вместо использования LINQ, сделайте объединение, а затем выполните ForEach для результата и вставьте значение в конечную таблицу данных.

Pseudocode:

dt1.Join(dt2).Where(...).ForEach(row => код для чтения содержимого анонимного объекта и добавления его в finalTable.Rows)

1
ответ дан 29 November 2019 в 05:29
поделиться
select new {
    ID = dataRows1.ID,  // no need to select dataRows2.ID, because of JOIN.
    A = dataRows1.A,
    B = dataRows1.B,
    C = dataRows2.C,
    D = dataRows2.D 
};
0
ответ дан 29 November 2019 в 05:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: