LINQ запрос к DataTable в C#: как выполнить выборку данных?
Решение: используйте метод AsEnumerable() и Field<T>()
Действительно, DataTable не реализует интерфейс IEnumerable<T>, необходимый для LINQ. Однако в .NET 3.5 и выше есть метод расширения AsEnumerable(), который возвращает EnumerableRowCollection<DataRow>. Это позволяет применять LINQ к строкам DataTable.
Вот правильный синтаксис для вашего примера:
using System.Data; // обязательно добавьте эту директиву
DataTable dt = GetEmployeesTable();
var result = from row in dt.AsEnumerable()
where row.Field<int>("Age") > 30
select row;
Обратите внимание на метод Field<T>("ColumnName"). Он безопасно извлекает значение столбца с приведением к нужному типу. Это лучше, чем прямое обращение через row["Age"], так как:
- Избегает исключений при
nullзначениях (возвращаетdefault(T)для типов-значений) - Работает быстрее, чем boxing/unboxing
- Обеспечивает строгую типизацию
Как преобразовать результат обратно в DataTable?
Если вам нужно получить новый DataTable из результата запроса, используйте метод CopyToDataTable():
DataTable filteredDt = dt.AsEnumerable()
.Where(row => row.Field<int>("Age") > 30)
.CopyToDataTable();
Важно: CopyToDataTable() доступен в пространстве имен System.Data.DataSetExtensions. Убедитесь, что у вас есть ссылка на сборку System.Data.DataSetExtensions.dll.
Полный пример с пояснениями
using System;
using System.Data;
using System.Linq;
class Program
{
static void Main()
{
// Создаем DataTable
DataTable dt = new DataTable("Employees");
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Age", typeof(int));
// Заполняем данными
dt.Rows.Add(1, "Иван", 25);
dt.Rows.Add(2, "Мария", 35);
dt.Rows.Add(3, "Петр", 40);
// LINQ запрос: сотрудники старше 30
var adults = from row in dt.AsEnumerable()
where row.Field<int>("Age") > 30
select new
{
Id = row.Field<int>("Id"),
Name = row.Field<string>("Name"),
Age = row.Field<int>("Age")
};
// Вывод результатов
foreach (var emp in adults)
{
Console.WriteLine($"{emp.Id}: {emp.Name}, {emp.Age} лет");
}
// Или сразу в новый DataTable
DataTable filteredDt = dt.AsEnumerable()
.Where(r => r.Field<int>("Age") > 30)
.CopyToDataTable();
}
}
Важные замечания
- Всегда используйте
Field<T>для типизированного доступа к столбцам - Если столбец может быть
null, используйтеField<int?>("Age")(nullable тип) - Метод
AsEnumerable()не копирует данные — он просто предоставляет итератор по строкам - Для обратной совместимости с .NET 2.0 можно использовать
SelectиWhereизSystem.Data, но LINQ удобнее
Альтернативный подход: использование Select() и Where() из DataTable
Если вы не можете использовать LINQ (например, работаете с .NET Framework 2.0), можно воспользоваться встроенными методами DataTable — Select() и Compute().
DataTable dt = GetEmployeesTable();
// Фильтрация через строку условия (синтаксис, похожий на SQL)
DataRow[] filteredRows = dt.Select("Age > 30");
// Можно сортировать
DataRow[] sortedRows = dt.Select("Age > 30", "Name ASC");
// Создаем новый DataTable из результата
DataTable result = dt.Clone(); // копируем структуру
foreach (DataRow row in filteredRows)
{
result.ImportRow(row);
}
Этот подход:
- Не требует дополнительных сборок (работает "из коробки")
- Проще для простых фильтраций
- Однако менее гибкий, чем LINQ: нет строгой типизации, сложнее делать сложные предикаты
Когда использовать: для быстрых прототипов или если вы ограничены старой версией .NET. Для современных проектов предпочтительнее LINQ с AsEnumerable().
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Логирование в C++ приложениях: лучшие практики и инструменты