Question
I am trying to run a LINQ query on a DataTable, but it seems that querying a DataTable directly is not straightforward.
For example, I tried something like this:
var results = from myRow in myDataTable
where myRow.Field<int>("RowNo") == 1
select myRow;
This does not compile as written. How can I make a LINQ query like this work with a DataTable in C#?
I was expecting DataTable to work directly with LINQ, so I want to understand the correct approach.
Short Answer
By the end of this page, you will understand why a DataTable cannot be queried directly with standard LINQ syntax, how AsEnumerable() makes LINQ work with table rows, and how to safely read column values using Field<T>(). You will also see practical examples, common mistakes, and a small project that filters data from a DataTable.
Concept
A DataTable stores rows of data in memory, but it does not directly implement the generic sequence interface that standard LINQ queries expect.
LINQ works best with collections such as:
IEnumerable<T>List<T>- arrays
- other generic sequences
A DataTable contains rows as DataRow objects, but to use LINQ query syntax like from ... where ... select ..., you usually need to convert the table into something LINQ can enumerate as a sequence of rows.
That is why C# provides the AsEnumerable() extension method for DataTable.
var results = myDataTable.AsEnumerable();
This gives you an IEnumerable<DataRow>, which LINQ can query.
Another important part is reading values from a DataRow. A DataRow stores column values as objects, so LINQ queries often use:
row.Field<int>("RowNo")
Mental Model
Think of a DataTable as a filing cabinet and each DataRow as one paper file.
LINQ expects a line of items it can walk through one by one, like files laid out on a desk. But a DataTable is not automatically presented that way for generic LINQ.
AsEnumerable() is the step that takes the files out of the cabinet and lays them on the desk so LINQ can inspect them one at a time.
Then Field<T>() is like reading a labeled field from each paper file in the correct data type:
"RowNo"as anint"Name"as astring"Price"as adecimal
So the process is:
- Convert the
DataTableinto an enumerable row sequence. - Read values from each row by column name.
- Filter or transform the rows with LINQ.
Syntax and Examples
The basic pattern is:
using System.Data;
using System.Linq;
var results = from row in myDataTable.AsEnumerable()
where row.Field<int>("RowNo") == 1
select row;
You can also write the same query with method syntax:
var results = myDataTable.AsEnumerable()
.Where(row => row.Field<int>("RowNo") == 1);
Example: filter rows by column value
using System;
using System.Data;
using System.Linq;
DataTable table = new DataTable();
table.Columns.Add("RowNo", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Rows.Add(1, "Alice");
table.Rows.Add(2, "Bob");
table.Rows.Add(1, "Charlie");
var results = from row table.AsEnumerable()
row.Field<>() ==
row;
( row results)
{
Console.WriteLine();
}
Step by Step Execution
Consider this code:
DataTable table = new DataTable();
table.Columns.Add("RowNo", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Rows.Add(1, "Alice");
table.Rows.Add(2, "Bob");
table.Rows.Add(1, "Charlie");
var results = table.AsEnumerable()
.Where(row => row.Field<int>("RowNo") == 1)
.Select(row => row.Field<string>("Name"));
Here is what happens step by step:
- A
DataTableis created. - Two columns are added:
RowNoasintNameasstring
- Three rows are inserted.
AsEnumerable()exposes the rows asIEnumerable<DataRow>.Where(...)checks each row:
Real World Use Cases
LINQ on DataTable is useful in many existing .NET applications.
Filtering imported data
If you load CSV or Excel data into a DataTable, you can use LINQ to find rows matching conditions:
- invalid records
- duplicate IDs
- rows missing required values
Working with database results
Some older systems still use SqlDataAdapter to fill a DataTable. LINQ makes it easier to:
- filter active users
- sort invoice rows
- extract only needed columns
Reporting and dashboards
A report may gather raw data into a DataTable, then use LINQ to:
- group values
- compute totals
- display only a subset of rows
Validation pipelines
Before saving data, LINQ can help detect:
- missing fields
- out-of-range values
- duplicate business keys
Real Codebase Usage
In real projects, developers often use LINQ on DataTable in small, focused ways rather than building huge query expressions.
Common patterns
Guard clauses before querying
if (table == null || table.Rows.Count == 0)
{
return;
}
This prevents null-reference problems and pointless queries.
Validation before reading typed values
var validRows = table.AsEnumerable()
.Where(row => !row.IsNull("RowNo"));
This is helpful when database data may contain DBNull.
Early filtering
var activeRows = table.AsEnumerable()
.Where(row => row.Field<bool>("IsActive"));
Filter early so later logic works on a smaller set.
Projection into models
Instead of passing DataRow around, many codebases map rows into objects:
var users = table.AsEnumerable()
.Select(row =>
{
Id = row.Field<>(),
Name = row.Field<>()
});
Common Mistakes
1. Querying the DataTable directly
Broken code:
var results = from row in myDataTable
where row.Field<int>("RowNo") == 1
select row;
Why it fails:
DataTableis not directly used asIEnumerable<DataRow>for this query syntax.
Fix:
var results = from row in myDataTable.AsEnumerable()
where row.Field<int>("RowNo") == 1
select row;
2. Using the wrong variable name inside the query
Broken code:
var results = from myRow in myDataTable.AsEnumerable()
where results.Field<int>("RowNo") == 1
results;
Comparisons
| Concept | What it works on | Best for | Notes |
|---|---|---|---|
DataTable.Select() | DataTable | Simple filtering with string expressions | Older API, less type-safe |
LINQ with AsEnumerable() | DataTable rows as IEnumerable<DataRow> | Readable filtering, projection, composition | Preferred for modern C# style |
List<T> with LINQ | Strongly typed objects | Most application business logic | Cleaner than raw DataTable usage |
DataTable.Select() vs LINQ
Cheat Sheet
// Required namespaces
using System.Data;
using System.Linq;
// Basic LINQ query on a DataTable
var results = from row in table.AsEnumerable()
where row.Field<int>("RowNo") == 1
select row;
// Method syntax
var results2 = table.AsEnumerable()
.Where(row => row.Field<int>("RowNo") == 1);
// Select one column
var names = table.AsEnumerable()
.Select(row => row.Field<string>("Name"));
// Handle nullable values
var rows = table.AsEnumerable()
.Where(row => row.Field<int?>("RowNo") == 1);
// Check for DBNull
var safeRows = table.AsEnumerable()
.Where(row => !row.IsNull("RowNo"));
// Convert filtered rows back to DataTable
var filteredRows = table.AsEnumerable()
.Where(row => row.Field<int>("RowNo") == 1);
DataTable filteredTable = filteredRows.Any()
? filteredRows.CopyToDataTable()
: table.Clone();
Rules to remember
FAQ
Why can't I use LINQ directly on a DataTable?
DataTable is not directly queried the same way as a generic IEnumerable<T> source in normal LINQ syntax. Use AsEnumerable() to expose its rows as IEnumerable<DataRow>.
What namespace do I need for AsEnumerable()?
You typically need System.Data and System.Linq. In many projects, the extension method support for DataTable also comes from the DataSet extensions assembly available in .NET.
What does Field() do in a DataRow?
It reads a column value from a DataRow and returns it as the specified type, such as int, string, or DateTime.
Can I return a DataTable after filtering with LINQ?
Yes. After filtering rows, call CopyToDataTable(). If the result may be empty, check with Any() first or return table.Clone().
Is DataTable.Select() better than LINQ?
Not usually. DataTable.Select() is fine for simple string-based filters, but LINQ is generally more readable, composable, and type-safe.
Mini Project
Description
Build a small in-memory employee filter using a DataTable and LINQ. This project demonstrates how to create a DataTable, add rows, filter by a numeric column, and project the results into readable output. It is useful because many .NET applications still receive tabular data from databases, files, or older APIs.
Goal
Create a program that stores employee data in a DataTable and prints only employees from a chosen department.
Requirements
- Create a
DataTablewith columns forId,Name, andDepartmentId. - Add at least five sample employee rows.
- Use
AsEnumerable()and LINQ to filter employees whereDepartmentIdequals 1. - Print the matching employee names to the console.
- Also show a version that projects matching rows into anonymous objects.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Array Initialization Syntaxes Explained
Learn all common C# array initialization syntaxes with examples, rules, comparisons, and mistakes beginners often make.