dotnet / dotnet/efcore

ExecuteUpdateAsync breaks with Many-To-Many and AutoInclude

Open
#35,523 1 comment 0 reactions 0 assignees View on GitHub
area-bulkupdate customer-reported
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

### Bug description

Configuring an entity to `AutoInclude` a many-to-many relationship renders `ExecuteUpdateAsync` dysfunctional.

I found https://github.com/dotnet/efcore/issues/30250 which is closed as duplicate to a resolved issue almost 2 years ago however it's reproducible in the most recent stable version. It seems the bug is only reproducible with many-to-many relationships at this point (the linked issue did not seem to cover that scenario).

### Your code

```xml


net9.0
enable
enable




```

```csharp
// Program.cs

using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services
.AddDbContext(options => options.UseSqlite("Data Source=:memory:"));

var app = builder.Build();

await using var scope = app.Services.CreateAsyncScope();
var brokenContext = scope.ServiceProvider.GetRequiredService();
await brokenContext.Database.MigrateAsync();
await brokenContext.BrokenModels.ExecuteUpdateAsync(calls => calls.SetProperty(m => m.Property, ""));

public class BrokenModel {
public Guid Id { get; set; }
public string Property { get; set; } = "";
public IEnumerable Relationships { get; set; }
}

public class BrokenRelationship {
public Guid Id { get; set; }
public IEnumerable BrokenModels { get; set; }
}

public class BrokenContext : DbContext{
public DbSet BrokenModels { get; set; } = null!;
public DbSet BrokenRelationships { get; set; } = null!;

public BrokenContext(DbContextOptions options): base(options) {
}

protected override void OnModelCreating(ModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);

modelBuilder.Entity().Navigation(m => m.Relationships).AutoInclude();
}
}
```

### Stack traces

```text
Unhandled exception. System.InvalidOperationException: The LINQ expression 'DbSet()
.Select(b0 => Include(
Entity: b0,
Navigation: Relationships, MaterializeCollectionNavigation(
Navigation: BrokenModel.Relationships,
Subquery: DbSet>("BrokenModelBrokenRelationship")
.Where(b1 => EF.Property(b0, "Id") != null && object.Equals(
objA: (object)EF.Property(b0, "Id"),
objB: (object)EF.Property(b1, "BrokenModelsId")))
.Join(
inner: DbSet(),
outerKeySelector: b1 => (object)EF.Property(b1, "RelationshipsId"),
innerKeySelector: b2 => (object)EF.Property(b2, "Id"),
resultSelector: (b1, b2) => new TransparentIdentifier, BrokenRelationship>(
Outer = b1,
Inner = b2
))
.Select(ti => NavigationExpandingExpressionVisitor.FetchJoinEntity, BrokenRelationship>(
joinEntity: ti.Outer,
targetEntity: ti.Inner))))
.ExecuteUpdate(calls => calls.SetProperty(
propertyExpression: m => m.Property,
valueExpression: ""))' could not be translated. Additional information: The following lambda argument to 'SetProperty' does not represent a valid property to be set: 'm => m.Property'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutorExpression[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass11_0`1.b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteCore[TResult](Expression query, Boolean async, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteUpdateAsync[TSource](IQueryable`1 source, Expression`1 setPropertyCalls, CancellationToken cancellationToken)
at Program.$(String[] args) in D:\playground\Program.cs:line 13
at Program.$(String[] args) in D:\playground\Program.cs:line 13
at Program.(String[] args)
```

### EF Core version

9.0.1

### Database provider

Microsoft.EntityFrameworkCore.Sqlite

### Target framework

.NET 9.0

### Operating system

Windows 11

### IDE

Rider 2024.3.3

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.