Skip to content

Commit

Permalink
Query: Enable materialzing collections of arbirtary shape in projection
Browse files Browse the repository at this point in the history
Part of #15611
Will send out separate PR to enable tests and fix edge case bugs

This PR
- Split out collection initialization/population for include to separate method due to type constraints
- Swallow materialize collection navigation/ToList in projection. Rest of unknown methods, we will fall into client eval
- Changes SqlTranslator to try translate & lift subquery always, allowing it to translate non Queryable defined but translatable methods
- Make identifiers nullable always to identify null keys & no correlation
  • Loading branch information
smitpatel committed Jun 28, 2019
1 parent 4b98b55 commit 4f1f019
Show file tree
Hide file tree
Showing 16 changed files with 549 additions and 317 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query.Expressions.Internal;
using Microsoft.EntityFrameworkCore.Query.Internal;

namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline
{
public class CollectionInitializingExpression : Expression, IPrintable
{
public CollectionInitializingExpression(
int collectionId, Expression parent, Expression parentIdentifier, Expression outerIdentifier, INavigation navigation, Type type)
{
CollectionId = collectionId;
Parent = parent;
ParentIdentifier = parentIdentifier;
OuterIdentifier = outerIdentifier;
Navigation = navigation;
Type = type;
}

protected override Expression VisitChildren(ExpressionVisitor visitor)
{
var parent = visitor.Visit(Parent);
var parentIdentifier = visitor.Visit(ParentIdentifier);
var outerIdentifier = visitor.Visit(OuterIdentifier);

return parent != Parent || parentIdentifier != ParentIdentifier || outerIdentifier != OuterIdentifier
? new CollectionInitializingExpression(CollectionId, parent, parentIdentifier, outerIdentifier, Navigation, Type)
: this;
}

public void Print(ExpressionPrinter expressionPrinter)
{
expressionPrinter.StringBuilder.AppendLine("InitializeCollection:");
using (expressionPrinter.StringBuilder.Indent())
{
expressionPrinter.StringBuilder.AppendLine($"CollectionId: {CollectionId}");
expressionPrinter.StringBuilder.AppendLine($"Navigation: {Navigation?.Name}");
expressionPrinter.StringBuilder.Append("Parent:");
expressionPrinter.Visit(Parent);
expressionPrinter.StringBuilder.AppendLine();
expressionPrinter.StringBuilder.Append("ParentIdentifier:");
expressionPrinter.Visit(ParentIdentifier);
expressionPrinter.StringBuilder.AppendLine();
expressionPrinter.StringBuilder.Append("OuterIdentifier:");
expressionPrinter.Visit(OuterIdentifier);
expressionPrinter.StringBuilder.AppendLine();
}
}

public override Type Type { get; }

public override ExpressionType NodeType => ExpressionType.Extension;

public int CollectionId { get; }
public Expression Parent { get; }
public Expression ParentIdentifier { get; }
public Expression OuterIdentifier { get; }
public INavigation Navigation { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Query.Expressions.Internal;
using Microsoft.EntityFrameworkCore.Query.Internal;

namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline
{
public class CollectionPopulatingExpression : Expression, IPrintable
{
public CollectionPopulatingExpression(RelationalCollectionShaperExpression parent, Type type, bool include)
{
Parent = parent;
Type = type;
Include = include;
}

protected override Expression VisitChildren(ExpressionVisitor visitor)
{
var parent = (RelationalCollectionShaperExpression)visitor.Visit(Parent);

return parent != Parent
? new CollectionPopulatingExpression(parent, Type, Include)
: this;
}

public void Print(ExpressionPrinter expressionPrinter)
{
expressionPrinter.StringBuilder.AppendLine("PopulateCollection:");
using (expressionPrinter.StringBuilder.Indent())
{
expressionPrinter.StringBuilder.Append("Parent:");
expressionPrinter.Visit(Parent);
}
}

public override Type Type { get; }

public override ExpressionType NodeType => ExpressionType.Extension;
public RelationalCollectionShaperExpression Parent { get; }
public bool Include { get; }
}
}
Loading

0 comments on commit 4f1f019

Please sign in to comment.