Skip to content

Commit

Permalink
Fix for including collection entity which contains JSON
Browse files Browse the repository at this point in the history
Resolves #28808
  • Loading branch information
smitpatel committed Sep 6, 2022
1 parent c11d084 commit b7b1f1b
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 49 deletions.
11 changes: 10 additions & 1 deletion src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,15 @@ Expression CopyProjectionToOuter(SelectExpression innerSelectExpression, Express

remappedConstant = Constant(newDictionary);
}
else if (constantValue is ValueTuple<int, List<ValueTuple<IProperty, int>>, string[]> tuple)
{
var newList = new List<ValueTuple<IProperty, int>>();
foreach (var item in tuple.Item2)
{
newList.Add((item.Item1, projectionIndexMap[item.Item2]));
}
remappedConstant = Constant((projectionIndexMap[tuple.Item1], newList, tuple.Item3));
}
else
{
remappedConstant = Constant(projectionIndexMap[(int)constantValue]);
Expand Down Expand Up @@ -1362,7 +1371,7 @@ Expression CopyProjectionToOuter(SelectExpression innerSelectExpression, Express
{
result[projectionMember] = expression switch
{
EntityProjectionExpression entityProjection => AddEntityProjection(entityProjection),
EntityProjectionExpression entityProjection => AddEntityProjection(entityProjection),
JsonQueryExpression jsonQueryExpression => AddJsonProjection(jsonQueryExpression, jsonProjectionDeduplicationMap[jsonQueryExpression]),
_ => Constant(AddToProjection((SqlExpression)expression, projectionMember.Last?.Name))
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public virtual ISetSource GetExpectedData()

public IReadOnlyDictionary<Type, object> EntitySorters { get; } = new Dictionary<Type, Func<object, object>>
{
{ typeof(EntityBasic), e => ((EntityBasic)e)?.Id },
{ typeof(JsonEntityBasic), e => ((JsonEntityBasic)e)?.Id },
{ typeof(JsonEntityBasicForReference), e => ((JsonEntityBasicForReference)e)?.Id },
{ typeof(JsonEntityBasicForCollection), e => ((JsonEntityBasicForCollection)e)?.Id },
Expand All @@ -36,6 +37,20 @@ public virtual ISetSource GetExpectedData()

public IReadOnlyDictionary<Type, object> EntityAsserters { get; } = new Dictionary<Type, Action<object, object>>
{
{
typeof(EntityBasic), (e, a) =>
{
Assert.Equal(e == null, a == null);
if (a != null)
{
var ee = (EntityBasic)e;
var aa = (EntityBasic)a;
Assert.Equal(ee.Id, aa.Id);
Assert.Equal(ee.Name, aa.Name);
}
}
},
{
typeof(JsonEntityBasic), (e, a) =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,18 +389,18 @@ public virtual Task Left_join_json_entities_complex_projection(bool async)
=> AssertQuery(
async,
ss => (from e1 in ss.Set<JsonEntitySingleOwned>()
join e2 in ss.Set<JsonEntityBasic>() on e1.Id equals e2.Id into g
from e2 in g.DefaultIfEmpty()
select new
{
Id1 = e1.Id,
Id2 = (int?)e2.Id,
e2,
e2.OwnedReferenceRoot,
e2.OwnedReferenceRoot.OwnedReferenceBranch,
e2.OwnedReferenceRoot.OwnedReferenceBranch.OwnedReferenceLeaf,
e2.OwnedReferenceRoot.OwnedReferenceBranch.OwnedCollectionLeaf
}),
join e2 in ss.Set<JsonEntityBasic>() on e1.Id equals e2.Id into g
from e2 in g.DefaultIfEmpty()
select new
{
Id1 = e1.Id,
Id2 = (int?)e2.Id,
e2,
e2.OwnedReferenceRoot,
e2.OwnedReferenceRoot.OwnedReferenceBranch,
e2.OwnedReferenceRoot.OwnedReferenceBranch.OwnedReferenceLeaf,
e2.OwnedReferenceRoot.OwnedReferenceBranch.OwnedCollectionLeaf
}),
elementSorter: e => (e.Id1, e?.Id2),
elementAsserter: (e, a) =>
{
Expand Down Expand Up @@ -664,6 +664,17 @@ public virtual Task Json_with_include_on_entity_collection(bool async)
new ExpectedInclude<JsonEntityBasic>(x => x.EntityCollection)),
entryCount: 43);

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Entity_including_collection_with_json(bool async)
=> AssertQuery(
async,
ss => ss.Set<EntityBasic>().Include(e => e.JsonEntityBasics),
elementAsserter: (e, a) => AssertInclude(
e, a,
new ExpectedInclude<EntityBasic>(x => x.JsonEntityBasics)),
entryCount: 0);

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Json_with_include_on_entity_collection_and_reference(bool async)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore.TestModels.JsonQuery
{
public class EntityBasic
{
public int Id { get; set; }
public string Name { get; set; }
public List<JsonEntityBasic> JsonEntityBasics { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public JsonQueryContext(DbContextOptions options)
{
}

public DbSet<EntityBasic> EntitiesBasic { get; set; }
public DbSet<JsonEntityBasic> JsonEntitiesBasic { get; set; }
public DbSet<JsonEntityBasicForReference> JsonEntitiesBasicForReference { get; set; }
public DbSet<JsonEntityBasicForCollection> JsonEntitiesBasicForCollection { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class JsonQueryData : ISetSource
{
public JsonQueryData()
{
EntitiesBasic = new List<EntityBasic>();
JsonEntitiesBasic = CreateJsonEntitiesBasic();
JsonEntitiesBasicForReference = CreateJsonEntitiesBasicForReference();
JsonEntitiesBasicForCollection = CreateJsonEntitiesBasicForCollection();
Expand All @@ -18,6 +19,7 @@ public JsonQueryData()
JsonEntitiesAllTypes = CreateJsonEntitiesAllTypes();
}

public IReadOnlyList<EntityBasic> EntitiesBasic { get; }
public IReadOnlyList<JsonEntityBasic> JsonEntitiesBasic { get; }
public IReadOnlyList<JsonEntityBasicForReference> JsonEntitiesBasicForReference { get; }
public IReadOnlyList<JsonEntityBasicForCollection> JsonEntitiesBasicForCollection { get; }
Expand Down Expand Up @@ -759,6 +761,11 @@ public static IReadOnlyList<JsonEntityAllTypes> CreateJsonEntitiesAllTypes()
public IQueryable<TEntity> Set<TEntity>()
where TEntity : class
{
if (typeof(TEntity) == typeof(EntityBasic))
{
return (IQueryable<TEntity>)EntitiesBasic.AsQueryable();
}

if (typeof(TEntity) == typeof(JsonEntityBasic))
{
return (IQueryable<TEntity>)JsonEntitiesBasic.AsQueryable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public override async Task Basic_json_projection_owner_entity(bool async)
await base.Basic_json_projection_owner_entity(async);

AssertSql(
@"SELECT [j].[Id], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$')
@"SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$')
FROM [JsonEntitiesBasic] AS [j]");
}

Expand Down Expand Up @@ -128,7 +128,7 @@ public override async Task Json_projection_with_deduplication(bool async)
await base.Json_projection_with_deduplication(async);

AssertSql(
@"SELECT [j].[Id], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$'), CAST(JSON_VALUE([j].[OwnedReferenceRoot],'$.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething') AS nvarchar(max))
@"SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$'), CAST(JSON_VALUE([j].[OwnedReferenceRoot],'$.OwnedReferenceBranch.OwnedReferenceLeaf.SomethingSomething') AS nvarchar(max))
FROM [JsonEntitiesBasic] AS [j]");
}

Expand All @@ -137,7 +137,7 @@ public override async Task Json_projection_with_deduplication_reverse_order(bool
await base.Json_projection_with_deduplication_reverse_order(async);

AssertSql(
@"SELECT JSON_QUERY([j].[OwnedReferenceRoot],'$'), [j].[Id], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$')
@"SELECT JSON_QUERY([j].[OwnedReferenceRoot],'$'), [j].[Id], [j].[EntityBasicId], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$')
FROM [JsonEntitiesBasic] AS [j]");
}

Expand Down Expand Up @@ -358,7 +358,7 @@ public override async Task Left_join_json_entities(bool async)
await base.Left_join_json_entities(async);

AssertSql(
@"SELECT [j].[Id], [j].[Name], JSON_QUERY([j].[OwnedCollection],'$'), [j0].[Id], [j0].[Name], JSON_QUERY([j0].[OwnedCollectionRoot],'$'), JSON_QUERY([j0].[OwnedReferenceRoot],'$')
@"SELECT [j].[Id], [j].[Name], JSON_QUERY([j].[OwnedCollection],'$'), [j0].[Id], [j0].[EntityBasicId], [j0].[Name], JSON_QUERY([j0].[OwnedCollectionRoot],'$'), JSON_QUERY([j0].[OwnedReferenceRoot],'$')
FROM [JsonEntitiesSingleOwned] AS [j]
LEFT JOIN [JsonEntitiesBasic] AS [j0] ON [j].[Id] = [j0].[Id]");
}
Expand All @@ -368,7 +368,7 @@ public override async Task Left_join_json_entities_complex_projection(bool async
await base.Left_join_json_entities_complex_projection(async);

AssertSql(
@"SELECT [j].[Id], [j0].[Id], [j0].[Name], JSON_QUERY([j0].[OwnedCollectionRoot],'$'), JSON_QUERY([j0].[OwnedReferenceRoot],'$')
@"SELECT [j].[Id], [j0].[Id], [j0].[EntityBasicId], [j0].[Name], JSON_QUERY([j0].[OwnedCollectionRoot],'$'), JSON_QUERY([j0].[OwnedReferenceRoot],'$')
FROM [JsonEntitiesSingleOwned] AS [j]
LEFT JOIN [JsonEntitiesBasic] AS [j0] ON [j].[Id] = [j0].[Id]");
}
Expand Down Expand Up @@ -558,7 +558,7 @@ public override async Task Json_with_include_on_json_entity(bool async)
await base.Json_with_include_on_json_entity(async);

AssertSql(
@"SELECT [j].[Id], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$')
@"SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$')
FROM [JsonEntitiesBasic] AS [j]");
}

Expand All @@ -567,7 +567,7 @@ public override async Task Json_with_include_on_entity_reference(bool async)
await base.Json_with_include_on_entity_reference(async);

AssertSql(
@"SELECT [j].[Id], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$'), [j0].[Id], [j0].[Name], [j0].[ParentId]
@"SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$'), [j0].[Id], [j0].[Name], [j0].[ParentId]
FROM [JsonEntitiesBasic] AS [j]
LEFT JOIN [JsonEntitiesBasicForReference] AS [j0] ON [j].[Id] = [j0].[ParentId]");
}
Expand All @@ -577,18 +577,29 @@ public override async Task Json_with_include_on_entity_collection(bool async)
await base.Json_with_include_on_entity_collection(async);

AssertSql(
@"SELECT [j].[Id], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$'), [j0].[Id], [j0].[Name], [j0].[ParentId]
@"SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$'), [j0].[Id], [j0].[Name], [j0].[ParentId]
FROM [JsonEntitiesBasic] AS [j]
LEFT JOIN [JsonEntitiesBasicForCollection] AS [j0] ON [j].[Id] = [j0].[ParentId]
ORDER BY [j].[Id]");
}

public override async Task Entity_including_collection_with_json(bool async)
{
await base.Entity_including_collection_with_json(async);

AssertSql(
@"SELECT [e].[Id], [e].[Name], [j].[Id], [j].[EntityBasicId], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$')
FROM [EntitiesBasic] AS [e]
LEFT JOIN [JsonEntitiesBasic] AS [j] ON [e].[Id] = [j].[EntityBasicId]
ORDER BY [e].[Id]");
}

public override async Task Json_with_include_on_entity_collection_and_reference(bool async)
{
await base.Json_with_include_on_entity_collection_and_reference(async);

AssertSql(
@"SELECT [j].[Id], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$'), [j0].[Id], [j0].[Name], [j0].[ParentId], [j1].[Id], [j1].[Name], [j1].[ParentId]
@"SELECT [j].[Id], [j].[EntityBasicId], [j].[Name], JSON_QUERY([j].[OwnedCollectionRoot],'$'), JSON_QUERY([j].[OwnedReferenceRoot],'$'), [j0].[Id], [j0].[Name], [j0].[ParentId], [j1].[Id], [j1].[Name], [j1].[ParentId]
FROM [JsonEntitiesBasic] AS [j]
LEFT JOIN [JsonEntitiesBasicForReference] AS [j0] ON [j].[Id] = [j0].[ParentId]
LEFT JOIN [JsonEntitiesBasicForCollection] AS [j1] ON [j].[Id] = [j1].[ParentId]
Expand Down
Loading

0 comments on commit b7b1f1b

Please sign in to comment.