Skip to content

Commit

Permalink
Fix to #30244 - Json column fails to materialize only when default in…
Browse files Browse the repository at this point in the history
…terceptor used

Problem was that when we build materializer expression, ValueBufferTryReadValue call that extracts values of keys is typed with key's CLR type. This fails for json as we visit the materializer expression, because calls to ValueBufferTryReadValue are replaced with array accesses to object[] that we store key values in. We should be using ValueBufferTryReadValue<object> when trying to get value for keys, like we do everywhere else, so that after the visitation expression types are correct.

Fixes #30244
  • Loading branch information
maumar committed Mar 5, 2023
1 parent 32fe1fd commit 5d35519
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 2 deletions.
10 changes: 8 additions & 2 deletions src/EFCore/Query/Internal/EntityMaterializerSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,14 @@ BlockExpression CreateAccessorDictionaryExpression()
Expression CreateAccessorReadExpression()
=> property is IServiceProperty serviceProperty
? serviceProperty.ParameterBinding.BindToParameter(bindingInfo)
: valueBufferExpression
.CreateValueBufferReadValueExpression(
: (property as IProperty)?.IsPrimaryKey() == true
? Expression.Convert(
valueBufferExpression.CreateValueBufferReadValueExpression(
typeof(object),
property.GetIndex(),
property),
property.ClrType)
: valueBufferExpression.CreateValueBufferReadValueExpression(
property.ClrType,
property.GetIndex(),
property);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,87 @@ public virtual async Task Missing_navigation_works_with_deduplication(bool async

#endregion

#region 30244

protected virtual void OnConfiguring30244(DbContextOptionsBuilder builder)
{
builder.AddInterceptors(new IssueReproMaterialization30244());
}

private class IssueReproMaterialization30244 : IMaterializationInterceptor
{
public InterceptionResult<object> CreatingInstance(
MaterializationInterceptionData materializationData,
InterceptionResult<object> result) => result;

public object CreatedInstance(
MaterializationInterceptionData materializationData,
object entity) => entity;

public InterceptionResult InitializingInstance(
MaterializationInterceptionData materializationData,
object entity, InterceptionResult result) => result;

public object InitializedInstance(
MaterializationInterceptionData materializationData,
object entity) => entity;
}

protected abstract void Seed30244(MyContext30244 ctx);

public class MyContext30244 : DbContext
{
public MyContext30244(DbContextOptions options)
: base(options)
{
}

public DbSet<TestEntity30244> TestEntities => Set<TestEntity30244>();

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TestEntity30244>().OwnsMany(e => e.Settings, nb => nb.ToJson());
}
}

public class TestEntity30244
{
public int Id { get; set; }
public string Name { get; set; }
public List<KeyValueSetting30244> Settings { get; set; }
}

public class KeyValueSetting30244
{
public KeyValueSetting30244(string key, string value)
{
Key = key;
Value = value;
}

public string Key { get; set; }
public string Value { get; set; }
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Materialize_entity_using_default_materialization_interceptor(bool async)
{
var contextFactory = await InitializeAsync<MyContext30244>(
onConfiguring: OnConfiguring30244,
seed: Seed30244);

using var context = contextFactory.CreateContext();

var entity = async
? await context.TestEntities.FirstOrDefaultAsync(x => x.Id == 1)
: context.TestEntities.FirstOrDefault(x => x.Id == 1);

Assert.NotNull(entity);
}

#endregion

#region ArrayOfPrimitives

[ConditionalTheory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,27 @@ protected override void Seed30028(MyContext30028 ctx)
N'{{""RootName"":""e4"",""Collection"":[{{""BranchName"":""e4 c1"",""Nested"":{{""LeafName"":""e4 c1 l""}}}},{{""BranchName"":""e4 c2"",""Nested"":{{""LeafName"":""e4 c2 l""}}}}],""OptionalReference"":{{""BranchName"":""e4 or"",""Nested"":{{""LeafName"":""e4 or l""}}}}}}')");
}

protected override void Seed30244(MyContext30244 ctx)
{
var entity = new TestEntity30244
{
Name = "TestIssue",
Settings = new List<KeyValueSetting30244>
{
new KeyValueSetting30244("Value1", "1"),
new KeyValueSetting30244("Value2", "9")
}
};

ctx.TestEntities.Add(entity);
ctx.SaveChanges();
}

public override Task Materialize_entity_using_default_materialization_interceptor(bool async)
{
return base.Materialize_entity_using_default_materialization_interceptor(async);
}

protected override void SeedArrayOfPrimitives(MyContextArrayOfPrimitives ctx)
{
var entity1 = new MyEntityArrayOfPrimitives
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,22 @@ protected override void Seed30028(MyContext30028 ctx)
'{{""RootName"":""e4"",""Collection"":[{{""BranchName"":""e4 c1"",""Nested"":{{""LeafName"":""e4 c1 l""}}}},{{""BranchName"":""e4 c2"",""Nested"":{{""LeafName"":""e4 c2 l""}}}}],""OptionalReference"":{{""BranchName"":""e4 or"",""Nested"":{{""LeafName"":""e4 or l""}}}}}}')");
}

protected override void Seed30244(MyContext30244 ctx)
{
var entity = new TestEntity30244
{
Name = "TestIssue",
Settings = new List<KeyValueSetting30244>
{
new KeyValueSetting30244("Value1", "1"),
new KeyValueSetting30244("Value2", "9")
}
};

ctx.TestEntities.Add(entity);
ctx.SaveChanges();
}

// issue #26708
protected override void OnConfiguringArrayOfPrimitives(DbContextOptionsBuilder builder)
=> base.AddOptions(builder.ConfigureWarnings(b => b.Ignore(SqliteEventId.CompositeKeyWithValueGeneration)));
Expand Down

0 comments on commit 5d35519

Please sign in to comment.