У меня есть следующий код, который заполняется 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 и поэтому нет многих выполнимых опций, доступных мимоходом данные в другом формате.
Вы уже просматривали эту страницу?
КАК: Реализовать вспомогательный класс 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 хороши, но они всего лишь расширения и не могут изменить указанные выше ограничения.
Извините, если я покажусь вам идиотом.
Я думаю, у вас должна быть готова финальная таблица (со всеми полями таблицы A и таблицы B).
И, вместо использования LINQ, сделайте объединение, а затем выполните ForEach
для результата и вставьте значение в конечную таблицу данных.
Pseudocode:
dt1.Join(dt2).Where(...).ForEach(row => код для чтения содержимого анонимного объекта и добавления его в finalTable.Rows)
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
};