Description
openedon Jan 4, 2024
This is about allowing an entity type to be used on the left-hand side (LHS) of an ExecuteUpdate setter, replacing the entire contents of the entity in the database with the right-hand side (RHS). #32058 did this for complex types.
Note that this could mean different things. Consider the following:
// 1. Assign reference nagivation from entity scalar subquery
_ = ctx.Blogs.ExecuteUpdate(setters => setters.SetProperty(b => b.BlogDetails, b => ctx.BlogDetails.Single(...)));
// 2. Assign reference nagivation from entity parameter
var blog = new Blog() { ... };
_ = ctx.Blogs.ExecuteUpdate(setters => setters.SetProperty(b => b.BlogDetails, blog));
// 3. Assign reference nagivation from inline entity
var blog = new Blog() { ... };
_ = ctx.Blogs.ExecuteUpdate(setters => setters.SetProperty(b => b.BlogDetails, new Blog { ... }));
For the 1st case, this would make all Blogs point to a single BlogDetails row in the database, based on the result of the subquery. This is reference assignment semantics.
For the 2nd and 3rd case, it's not immediately clear what should happen. We could overwrite each Blog's BlogDetail columns (value assignment semantics); but if BlogDetails is optional and some Blog doesn't have one, we'd need to insert a new one - but SQL UPDATE doesn't allow this (so ExecuteUpdate would need to do INSERTs as well). An alternative approach would be to conserve reference assignment semantics (these are entity types after all), and only extract the key from the parameterized blog
, assigning the foreign key property only (or again, overwrite the BlogDetails properties as well, which requires updating two tables, assuming Blogs has the foreign key).
For top-level entities things are slightly different:
// 4. Assign top-level entity from parameterized entity instance
_ = ctx.Blogs.ExecuteUpdate(setters => setters.SetProperty(b => b, blog));
// 5. Contrived: assign top-level entity from entity scalar subquery
_ = ctx.Blogs.ExecuteUpdate(setters => setters.SetProperty(b => b, b => ctx.BlogDetails.Single(...));
Here, there's no possibility of reference assignment (there's no reference) - (4) can only overwrite the columns in existing rows. (5) seems contrived but would presumably do the same.
So it seems like the behavior could depend both on the RHS (parameter or database entity instance) and on the LHS (top-level entity or navigation).
Finally, there's also the question of owned entity types; the only thing that makes sense here is to overwrite (value assignment), since the same owned entity type can't be owned by multiple owners. Given that we have complex types and owned types may be deprioritized going forward, we probably shouldn't do this if it's too much work.