-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Description
Problem
When using init for properties that are set up as a primitive collection saving them to the database works, but trying to materialize them leads to a System.ArgumentException: 'Expression must be writeable (Parameter 'left')'.
This happens with both MsSql as well as sqlite providers (probably all others as well, but have only tested those 2).
This does NOT happen when using a "plain" primitive collection as a top level property of an entity. init is fine here.
Code and Repro
You can find a runnable sample showing the problem here: https://github.com/Jejuni/PrimitiveCollectionInJsonInitProblem
The code is adapted from the samples referenced in the documentation: https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew#primitive-collections-in-json-documents
These are the entities and DbContext.
Note the only relevant change from the official sample is the change from set to init on the primitive collection DaysVisited.
public class Pub
{
public Pub(string name)
{
Name = name;
}
public int Id { get; set; }
public string Name { get; set; }
public Visits Visits { get; set; } = null!;
}
public class Visits
{
public string? LocationTag { get; set; }
public List<DateOnly> DaysVisited { get; init; } = null!; // Change this from `init` to `set` and it works
}
internal class TestContext : DbContext
{
public static bool UseSqlite { get; set; }
public DbSet<Pub> Pubs => Set<Pub>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (UseSqlite)
optionsBuilder.UseSqlite("DataSource=sqlite.db");
else
optionsBuilder.UseSqlServer(
"Server=localhost,5433;Initial Catalog=PrimitiveCollectionsProblem;User Id=sa;Password=Pass@word;TrustServerCertificate=true");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Pub>(
b => { b.OwnsOne(e => e.Visits).ToJson(); });
}
}The code in Program.cs shows the problem:
TestContext.UseSqlite = false;
await using (var ctx = new TestContext())
{
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();
}
await using (var ctx = new TestContext())
{
var user = new Pub("MyPub")
{
Visits = new Visits
{
LocationTag = "tag",
DaysVisited = new List<DateOnly> { new(2023, 1, 1) }
}
};
ctx.Pubs.Add(user);
await ctx.SaveChangesAsync();
}
await using (var ctx = new TestContext())
{
var pubs = await ctx.Pubs.ToListAsync(); // Exception thrown here
}Exception Stack Trace
System.ArgumentException
HResult=0x80070057
Message=Expression must be writeable (Parameter 'left')
Source=System.Linq.Expressions
StackTrace:
at System.Linq.Expressions.Expression.RequiresCanWrite(Expression expression, String paramName)
at System.Linq.Expressions.Expression.Assign(Expression left, Expression right)
at System.Linq.Expressions.Expression.MakeBinary(ExpressionType binaryType, Expression left, Expression right, Boolean liftToNull, MethodInfo method, LambdaExpression conversion)
at System.Linq.Expressions.Expression.MakeBinary(ExpressionType binaryType, Expression left, Expression right)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.JsonEntityMaterializerRewriter.ValueBufferTryReadValueMethodsReplacer.VisitBinary(BinaryExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.JsonEntityMaterializerRewriter.VisitSwitch(SwitchExpression switchExpression)
at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.JsonEntityMaterializerRewriter.VisitConditional(ConditionalExpression conditionalExpression)
at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.JsonEntityMaterializerRewriter.VisitConditional(ConditionalExpression conditionalExpression)
at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.JsonEntityMaterializerRewriter.Rewrite(BlockExpression jsonEntityShaperMaterializer)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.CreateJsonShapers(IEntityType entityType, Boolean nullable, ParameterExpression jsonReaderDataParameter, ParameterExpression keyValuesParameter, Expression parentEntityExpression, INavigation navigation)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression, RelationalCommandCache& relationalCommandCache, IReadOnlyList`1& readerColumns, LambdaExpression& relatedDataLoaders, Int32& collectionId)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
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__DisplayClass12_0`1.<ExecuteAsync>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
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.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Collections.Generic.IAsyncEnumerable<TEntity>.GetAsyncEnumerator(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.<ToListAsync>d__67`1.MoveNext()
at Program.<<Main>$>d__0.MoveNext() in C:\Users\Path\PrimitiveCollectionInJsonInitProblem\PrimitiveCollectionInJsonInitProblem\Program.cs:line 29
at Program.<<Main>$>d__0.MoveNext() in C:\Users\Path\PrimitiveCollectionInJsonInitProblem\PrimitiveCollectionInJsonInitProblem\Program.cs:line 33
Include provider and version information
EF Core version: 8.0
Database provider: (e.g. Microsoft.EntityFrameworkCore.SqlServer / Sqlite)
Target framework: (e.g. .NET 8.0)
Operating system:
IDE: (e.g. Visual Studio 2022 17.8)