A DbSet<T> property on an EF Core DbContext exposes entities of type T for querying and lookup. It also helps EF Core discover those entities and map them to the database. For example, a Recipes property gives an application a starting point for working with Recipe entities. section 12.2.2 section 12.4.2
Listing 12.3 Defining the application DbContext
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) #1
: base(options) { } #1
public DbSet<Recipe> Recipes { get; set; } #2
}
See how AppDbContext declares its DbSet<Recipe> property. Other top-level entity types can have their own DbSet properties. section 12.2.2
An entity does not always need its own DbSet property. Ingredient is included in the model through Recipe.Ingredients; to reach ingredients in this example, navigate through a recipe. section 12.2.2
Common operations start at the DbSet but finish in different ways:
- Query: chain LINQ Where() and Select() calls on Recipes, then call ToListAsync() to execute the database query. Select() can produce view models while fetching only needed columns. section 12.4.2
- Update: call Recipes.FindAsync(id), change the returned entity, then call SaveChangesAsync() on the DbContext. Find may return an already-tracked entity without a database call. section 12.4.4
Listing 12.7 Loading a list of items using EF Core in RecipeService
public async Task<ICollection<RecipeSummaryViewModel>> GetRecipes()
{
return await _context.Recipes #1
.Where(r => !r.IsDeleted)
.Select(r => new RecipeSummaryViewModel #2
{ #2
Id = r.RecipeId, #2
Name = r.Name, #2
TimeToCook = $"{r.TimeToCook.TotalMinutes}mins" #2
})
.ToListAsync(); #3
}
#1 A query starts from a DbSet property.
#2 EF Core queries only the Recipe columns it needs to map the view model correctly.
#3 Executes the SQL query and creates the final view models
Follow a complete list query from the Recipes DbSet through filtering and projection to ToListAsync(). section 12.4.2
Marking a recipe as deleted
Look up a recipe with Recipes.FindAsync(recipeId), set its IsDeleted property to true, and call _context.SaveChangesAsync(). A list query can then exclude it with Where(r => !r.IsDeleted). The DbSet supplies the lookup and query; the DbContext saves the change. section 12.4.4 section 12.4.2


