IQueryable is a LINQ-specific interface that extends IEnumerable. In EF Core, it gives a query over a DbSet a type that can be modified as filtering, ordering, or paging requirements become known. section 5.2 section 5.4.1
Common LINQ operations serve different jobs:
- Where filters; Select projects; OrderBy and OrderByDescending sort. section 5.2
- Skip and Take page results; FirstOrDefault retrieves an element matching a condition. section 5.2 section 5.4.1
- ToList, ToArray, and ToDictionary convert a query to a collection. Conversion materializes it, retrieving all its entities. section 5.2
Save before querying
Add Book objects to a CatalogContext, call SaveChanges(), then iterate dbContext.Books.OrderBy(b => b.Id). Moving SaveChanges() after the query leaves no books to retrieve: the DbSet accesses database contents, not additions still held only in code. section 5.2
Listing 5.25 Adding a new controller that allows requesting a list of books
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace ManningBooksApi.Controllers; #1
[ApiController] #2
[Route("[controller]")] #3
public class CatalogController : ControllerBase
{
private readonly CatalogContext _dbContext; #4
public CatalogController(
CatalogContext dbContext) #5
{
_dbContext = dbContext;
}
[HttpGet] #6
public IAsyncEnumerable<Book> GetBooks( #7
string? titleFilter = null) #8
{
IQueryable<Book> query = _dbContext.Books #9
.Include(b => b.Ratings)
.AsNoTracking(); #10
if (titleFilter != null)
{
query = query.Where(b =>
b.Title.ToLower().Contains(titleFilter.ToLower()));
}
return query.AsAsyncEnumerable(); #11
}
}
The GET action starts with an IQueryable<Book> from the Books DbSet and applies Include and AsNoTracking. Keeping the value queryable allows the action to modify it for request options; an accompanying exercise adds sorting and paging parameters. section 5.4.1



