C#
LINQ
IQueryable
List
data-conversion

How change ListT data to IQueryableT data

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Converting a List<T> to IQueryable<T> in C# is done with a single call to .AsQueryable(). However, the resulting IQueryable<T> does not gain database-side query translation — it still evaluates in memory using LINQ to Objects. The conversion is useful for creating testable code, building unified APIs that accept IQueryable<T>, or providing an IQueryable<T> interface over in-memory data for mocking purposes.

Basic Conversion with AsQueryable()

csharp
1using System.Linq;
2
3List<string> names = new List<string> { "Alice", "Bob", "Charlie" };
4
5// Convert to IQueryable<T>
6IQueryable<string> queryable = names.AsQueryable();
7
8// Query it like any IQueryable
9var result = queryable.Where(n => n.StartsWith("A")).ToList();
10// result: ["Alice"]

AsQueryable() wraps the list in an EnumerableQuery<T> that implements IQueryable<T> while delegating execution to LINQ to Objects.

IQueryable vs IEnumerable vs List

csharp
1// List<T>: concrete in-memory collection
2List<int> list = new List<int> { 1, 2, 3, 4, 5 };
3
4// IEnumerable<T>: lazy forward-only iteration
5IEnumerable<int> enumerable = list.Where(x => x > 2);
6
7// IQueryable<T>: expression tree-based querying
8IQueryable<int> queryable = list.AsQueryable().Where(x => x > 2);
FeatureList<T>IEnumerable<T>IQueryable<T>
StorageIn-memoryDeferredDeferred
ExecutionImmediateClient-sideProvider-dependent
Expression treesNoNoYes
Can translate to SQLNoNoYes (with EF/LINQ provider)

When AsQueryable() Is Useful

Unit Testing with Mock Data

csharp
1public interface IUserRepository
2{
3    IQueryable<User> GetUsers();
4}
5
6// Real implementation queries the database
7public class UserRepository : IUserRepository
8{
9    private readonly DbContext _context;
10
11    public IQueryable<User> GetUsers() => _context.Users;
12}
13
14// Test implementation uses in-memory data
15public class FakeUserRepository : IUserRepository
16{
17    private readonly List<User> _users = new()
18    {
19        new User { Id = 1, Name = "Alice", Age = 30 },
20        new User { Id = 2, Name = "Bob", Age = 25 },
21    };
22
23    public IQueryable<User> GetUsers() => _users.AsQueryable();
24}

Unified API That Accepts IQueryable

csharp
1public static List<T> ApplyPaging<T>(IQueryable<T> query, int page, int pageSize)
2{
3    return query
4        .Skip((page - 1) * pageSize)
5        .Take(pageSize)
6        .ToList();
7}
8
9// Works with Entity Framework
10var dbUsers = ApplyPaging(context.Users, page: 1, pageSize: 10);
11
12// Also works with in-memory data
13var list = new List<User> { /* ... */ };
14var memUsers = ApplyPaging(list.AsQueryable(), page: 1, pageSize: 10);

What AsQueryable() Does NOT Do

csharp
1List<User> users = LoadAllUsers();  // 1 million users in memory
2
3IQueryable<User> queryable = users.AsQueryable();
4
5// This does NOT translate to SQL — it still filters in memory
6var adults = queryable.Where(u => u.Age >= 18).ToList();
7// All 1 million users are iterated in memory
8
9// Compare with Entity Framework's IQueryable
10var dbAdults = context.Users.Where(u => u.Age >= 18).ToList();
11// Translates to: SELECT * FROM Users WHERE Age >= 18
12// Only matching rows are loaded from the database

AsQueryable() creates expression trees from your LINQ queries, but without a database provider, those expression trees are compiled into delegates and executed in memory — exactly like IEnumerable<T>.

Converting Back: AsEnumerable() and ToList()

csharp
1IQueryable<User> queryable = context.Users.Where(u => u.Age > 18);
2
3// Switch to client-side evaluation
4IEnumerable<User> enumerable = queryable.AsEnumerable();
5// Further operations use LINQ to Objects, not SQL
6
7// Materialize into a list
8List<User> list = queryable.ToList();
9
10// Convert IQueryable to List then back to IQueryable
11List<User> cached = queryable.ToList();
12IQueryable<User> reQueryable = cached.AsQueryable();

Building Dynamic Queries

One advantage of IQueryable<T> is composing queries before execution:

csharp
1public IQueryable<User> BuildQuery(List<User> source, string nameFilter, int? minAge)
2{
3    IQueryable<User> query = source.AsQueryable();
4
5    if (!string.IsNullOrEmpty(nameFilter))
6    {
7        query = query.Where(u => u.Name.Contains(nameFilter));
8    }
9
10    if (minAge.HasValue)
11    {
12        query = query.Where(u => u.Age >= minAge.Value);
13    }
14
15    return query;  // Not executed until enumerated
16}
17
18// Usage
19var users = new List<User> { /* ... */ };
20var query = BuildQuery(users, "Ali", 25);
21var results = query.OrderBy(u => u.Name).ToList();  // Executed here

Common Pitfalls

  • Expecting database query translation: list.AsQueryable().Where(...) does NOT generate SQL. The data is already in memory, and all filtering happens client-side. Only IQueryable<T> backed by a LINQ provider (like Entity Framework) translates to SQL.
  • Performance misconceptions: Converting a List<T> to IQueryable<T> does not improve performance. The underlying data is still iterated in memory. It only changes the API surface to IQueryable<T>.
  • Test behavior mismatch: LINQ to Objects (from AsQueryable()) supports operations that LINQ to SQL does not (e.g., StringComparison overloads, custom method calls). A test passing with AsQueryable() may fail against a real database.
  • Deferred execution surprises: AsQueryable() queries are deferred — they execute when enumerated. If the source List<T> is modified between creating the query and enumerating it, the results reflect the modified list.
  • Using AsQueryable() on DbSet: Calling AsQueryable() on an Entity Framework DbSet<T> is redundant — DbSet<T> already implements IQueryable<T>. The extra call has no effect.

Summary

  • Use list.AsQueryable() to convert List<T> to IQueryable<T>
  • The conversion is useful for testing, unified APIs, and dynamic query building
  • AsQueryable() does NOT enable database query translation — it still uses LINQ to Objects
  • Only IQueryable<T> backed by a LINQ provider (Entity Framework, NHibernate) translates queries to SQL
  • For real deferred database queries, use DbContext.Set<T>() or DbSet<T> directly

Course illustration
Course illustration

All Rights Reserved.