Update the 'API with read/write endpoints, using Entity Framework" scaffolder for EF Core 7
See original GitHub issue@davidfowl @ajcvickers @JeremyLikness @jcjiang
Updates to be made to the “API with read/write endpoints, using Entity Framework” scaffolder to better utilize new features in EF Core 7. We should do a similar review of the MVC API scaffolders too @brunolins16 .
~Default the generated DbContext
type to be configured for no-tracking~
~In order to better optimize the generated code for read-centric web APIs and to better align with the other changes being specified in this issue, when a new DbContext
is generated by the scaffolder it should be configured for no-tracking by overriding the OnConfiguring
method and calling optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
, e.g.:~
Generate type-specific names for identifiers
In cases today where the generated code generates a model type instance with the identifier model
, should be changed to generate an identifier name derived from the type name by simply converting the type name to camel case, e.g. Todo
becomes todo
. We already do this for the parameters to the endpoint delegates and should use the same pattern when necessary in the generated delegate bodies.
Update the “Get[Model]ById” endpoint to use FirstOrDefaultAsync
Replace use of FindAsync
with FirstOrDefaultAsync
. The FindAsync
method performs extra work that isn’t relevant in the use case of the generated code.
Example (in this case not using TypedResults
or OpenAPI but all variants should be updated):
group.MapGet("/{id}", async (int id, TodosDbContext db) =>
{
return await db.Todo.AsNoTracking()
.FirstOrDefaultAsync(todo => todo.Id == id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound();
})
Update the “Update[Model]” endpoint to use ExecuteUpdateAsync
Use the new ExecuteUpdateAsync
method in EF Core 7 to avoid multiple roundtrips to the database. This will require the scaffolder to call into the EF model details to get the list of members to generate property setter calls for (see @ajcvickers for details).
Example:
group.MapPut("/{id}", async (int id, Todo todo, TodosDbContext db) =>
{
var affected = await db.Todo
.Where(todo => todo.Id == id)
.ExecuteUpdateAsync(setters => setters
.SetProperty(t => t.Title, todo.Title)
.SetProperty(t => t.IsComplete, todo.IsComplete)
);
return affected == 1 ? Results.Ok() : Results.NotFound();
}
Update the “Delete[Model]” endpoint to use ExecuteDeleteAsync
Use the new ExecuteDeleteAsync
method in EF Core 7 to avoid multiple roundtrips to the database.
Example:
group.MapDelete("/{id}", async (int id, TodosDbContext db) =>
{
var affected = await db.Todo
.Where(todo => todo.Id == id)
.ExecuteDeleteAsync();
return affected == 1 ? Results.Ok() : Results.NotFound();
})
Issue Analytics
- State:
- Created 10 months ago
- Reactions:1
- Comments:8 (8 by maintainers)
Top GitHub Comments
AsNoTracking
is not needed forExecuteUpdateAsync
orExecuteDeleteAsync
since these queries return no entities and hance are effectively no-tracking all the time.Riiiight. I see the point, if I’m adding new APIs to existing with it configured differently … gotcha. Given that and the fact it’s only one query, it makes sense to me to keep the default and add AsNoTracking to the one call that needs it.