Support ExecuteUpdate when the value selector is a collection
- Dominant language
- C#
- Stars
- 14.8k
- Forks
- 3.4k
- PR merge metrics
- PR metrics pending
Description
The following query fails:
```c#
await db.Test
.ExecuteUpdateAsync(c => c.SetProperty(x => x.TextParts, x => x.TextParts.Concat(arr)));
```
The 1st reason for the failure is #32493; this can be worked around by extracting the lambda to a preceding Select:
```c#
await ctx.Blogs
.Select(b => new { Blog = b, NewTextParts = b.TextParts.Concat(arr) })
.ExecuteUpdateAsync(c => c.SetProperty(x => x.Blog.TextParts, x => x.NewTextParts));
```
At this point we run against other failures:
1. If the type of the property being set (Blog.TextParts) and the type coming out of the value lambda is different, we attempt to apply a Convert node ([code](https://github.com/dotnet/efcore/blob/main/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs#L1512)) which can fail (e.g. array property, List coming out of the selector - at least in PG).
2. More importantly, the expression translated for NewTextParts in the anonymous object above is a CollectionResultExpression - this is what Select() returns when the thing being selected is an enumerable. We then attempt to (re-)translate that and fail.
* We should be able to make this work.
* But more generally, this raises the question of why we attempt to translate twice - once when translating the Select, and another time when translating the ExecuteUpdate's value selector lambda, into which we remap the lambda parameter (inserting a CollectionResultExpression into the lambda).
* This can be another argument against out general remapping approach. Instead of doing a pre-pass the remap the lambda parameter, and then having to skip re-translating the thing we remapped, if SQL translator simply encountered a parameter it could process it accordingly.
Originally raised by @srasch in https://github.com/npgsql/efcore.pg/issues/3001
Contributor guide
Assessment
This issue has not been assessed yet.