Skip to content

Commit

Permalink
Correctig navigatgion expansion handling of owned navigations
Browse files Browse the repository at this point in the history
Navigation expansion should not try expand owned navigations. We still add them to navigation tree for tracking purposes but we don't inject LeftJoin calls when processing them.
Collection navigations are converted directly to NavigationExpansionExpressions whose root is the navigation itself to avoid rewrite to a subquery.
  • Loading branch information
maumar committed Jun 4, 2019
1 parent e6acad1 commit 4b4d434
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 43 deletions.
13 changes: 11 additions & 2 deletions src/EFCore/ChangeTracking/Internal/StateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,13 +288,22 @@ public virtual InternalEntityEntry CreateEntry(IDictionary<string, object> value
}

var valueBuffer = new ValueBuffer(valuesArray);

var entity = entityType.HasClrType()
? EntityMaterializerSource.GetMaterializer(entityType)(
new MaterializationContext(valueBuffer, Context))
: null;

var entry = _internalEntityEntryFactory.Create(this, entityType, entity, valueBuffer);
i = 0;
var shadowPropertyValuesArray = new object[entityType.ShadowPropertyCount()];
foreach (var shadowProperty in entityType.GetProperties().Where(p => p.IsShadowProperty()))
{
shadowPropertyValuesArray[i++] = values.TryGetValue(shadowProperty.Name, out var shadowValue)
? shadowValue
: shadowProperty.ClrType.GetDefaultValue();
}

var shadowPropertyValueBuffer = new ValueBuffer(shadowPropertyValuesArray);
var entry = _internalEntityEntryFactory.Create(this, entityType, entity, shadowPropertyValueBuffer);

UpdateReferenceMaps(entry, EntityState.Detached, null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Extensions.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
Expand Down Expand Up @@ -182,8 +183,13 @@ var transparentIdentifierCtorInfo
foreach (var mapping in state.SourceMappings)
{
var nodes = include
? mapping.NavigationTree.Flatten().Where(n => (n.Included == NavigationTreeNodeIncludeMode.ReferenceComplete || n.ExpansionMode == NavigationTreeNodeExpansionMode.ReferenceComplete) && n != navigationTree)
: mapping.NavigationTree.Flatten().Where(n => n.ExpansionMode == NavigationTreeNodeExpansionMode.ReferenceComplete && n != navigationTree);
? mapping.NavigationTree.Flatten().Where(n => (n.Included == NavigationTreeNodeIncludeMode.ReferenceComplete
|| n.ExpansionMode == NavigationTreeNodeExpansionMode.ReferenceComplete
|| n.Navigation.ForeignKey.IsOwnership)
&& n != navigationTree)
: mapping.NavigationTree.Flatten().Where(n => (n.ExpansionMode == NavigationTreeNodeExpansionMode.ReferenceComplete
|| n.Navigation.ForeignKey.IsOwnership)
&& n != navigationTree);

foreach (var navigationTreeNode in nodes)
{
Expand Down
35 changes: 25 additions & 10 deletions src/EFCore/Query/NavigationExpansion/NavigationTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ private NavigationTreeNode(
Included = NavigationTreeNodeIncludeMode.NotNeeded;
}

// for ownership don't mark for include or expansion
// just track the navigations in the tree in the original form
// they will be expanded/translated later in the pipeline
if (navigation.ForeignKey.IsOwnership)
{
ExpansionMode = NavigationTreeNodeExpansionMode.NotNeeded;
Included = NavigationTreeNodeIncludeMode.NotNeeded;

ToMapping = parent.ToMapping.ToList();
ToMapping.Add(navigation.Name);
}

foreach (var parentFromMapping in parent.FromMappings)
{
var newMapping = parentFromMapping.ToList();
Expand Down Expand Up @@ -92,17 +104,20 @@ public static NavigationTreeNode Create(
var existingChild = parent.Children.Where(c => c.Navigation == navigation).SingleOrDefault();
if (existingChild != null)
{
if (include && existingChild.Included == NavigationTreeNodeIncludeMode.NotNeeded)
{
existingChild.Included = navigation.IsCollection()
? NavigationTreeNodeIncludeMode.Collection
: NavigationTreeNodeIncludeMode.ReferencePending;
}
else if (!include && existingChild.ExpansionMode == NavigationTreeNodeExpansionMode.NotNeeded)
if (!navigation.ForeignKey.IsOwnership)
{
existingChild.ExpansionMode = navigation.IsCollection()
? NavigationTreeNodeExpansionMode.Collection
: NavigationTreeNodeExpansionMode.ReferencePending;
if (include && existingChild.Included == NavigationTreeNodeIncludeMode.NotNeeded)
{
existingChild.Included = navigation.IsCollection()
? NavigationTreeNodeIncludeMode.Collection
: NavigationTreeNodeIncludeMode.ReferencePending;
}
else if (!include && existingChild.ExpansionMode == NavigationTreeNodeExpansionMode.NotNeeded)
{
existingChild.ExpansionMode = navigation.IsCollection()
? NavigationTreeNodeExpansionMode.Collection
: NavigationTreeNodeExpansionMode.ReferencePending;
}
}

return existingChild;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,9 @@ protected override Expression VisitExtension(Expression extensionExpression)
&& navigationBindingExpression.NavigationTreeNode.Navigation is INavigation lastNavigation
&& lastNavigation.IsCollection())
{
var result = CreateCollectionNavigationExpression(navigationBindingExpression.NavigationTreeNode, navigationBindingExpression.RootParameter, navigationBindingExpression.SourceMapping);

return result;
return lastNavigation.ForeignKey.IsOwnership
? NavigationExpansionHelpers.CreateNavigationExpansionRoot(navigationBindingExpression, lastNavigation.GetTargetType(), lastNavigation)
: CreateCollectionNavigationExpression(navigationBindingExpression.NavigationTreeNode, navigationBindingExpression.RootParameter, navigationBindingExpression.SourceMapping);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ FROM root c
WHERE ((c[""Discriminator""] = ""LeafB"") OR ((c[""Discriminator""] = ""LeafA"") OR ((c[""Discriminator""] = ""Branch"") OR (c[""Discriminator""] = ""OwnedPerson""))))");
}

public override void Navigation_rewrite_on_owned_reference()
public override void Navigation_rewrite_on_owned_reference_projecting_entity()
{
base.Navigation_rewrite_on_owned_reference();
base.Navigation_rewrite_on_owned_reference_projecting_entity();

AssertSql(
@"SELECT c
Expand Down
Loading

0 comments on commit 4b4d434

Please sign in to comment.