Skip to content

Commit 5056f62

Browse files
authored
Merge pull request #181 from servicetitan/upstream/optimize_ProjectionExpression
Refactor & optimize ProjectionExpression, TranslatedQuery
2 parents 34b30ed + ba89143 commit 5056f62

15 files changed

Lines changed: 127 additions & 228 deletions

Orm/Xtensive.Orm/Core/ParameterContext.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2008-2020 Xtensive LLC.
1+
// Copyright (C) 2008-2021 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Alex Kofman
@@ -7,7 +7,7 @@
77
using System;
88
using System.Collections.Generic;
99
using System.Diagnostics;
10-
10+
using Tuple = Xtensive.Tuples.Tuple;
1111

1212
namespace Xtensive.Core
1313
{
@@ -42,9 +42,15 @@ public TValue GetValue<TValue>(Parameter<TValue> parameter)
4242
/// <summary>
4343
/// Initializes new instance of this type.
4444
/// </summary>
45-
public ParameterContext(ParameterContext outerContext = null)
45+
public ParameterContext(ParameterContext outerContext = null, IReadOnlyDictionary<Parameter<Tuple>, Tuple> tupleParameterBindings = null)
4646
{
4747
this.outerContext = outerContext;
48+
49+
if (tupleParameterBindings != null) {
50+
foreach (var (parameter, tuple) in tupleParameterBindings) {
51+
SetValue(parameter, tuple);
52+
}
53+
}
4854
}
4955
}
5056
}

Orm/Xtensive.Orm/Orm/DelayedQuery.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,7 @@ internal DelayedQuery(Session session, TranslatedQuery translatedQuery, Paramete
9797
LifetimeToken = session.GetLifetimeToken();
9898

9999
materializer = translatedQuery.Materializer;
100-
parameterContext = new ParameterContext(outerParameterContext);
101-
foreach (var (parameter, tuple) in translatedQuery.TupleParameterBindings) {
102-
parameterContext.SetValue(parameter, tuple);
103-
}
100+
parameterContext = new ParameterContext(outerParameterContext, translatedQuery.TupleParameterBindings);
104101

105102
Task = new QueryTask(translatedQuery.DataSource, LifetimeToken, parameterContext);
106103
}

Orm/Xtensive.Orm/Orm/Linq/Expressions/GroupingExpression.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,7 @@ public override Expression ReplaceApplyParameter(ApplyParameter newApplyParamete
9090
return new GroupingExpression(Type, OuterParameter, DefaultIfEmpty, ProjectionExpression, ApplyParameter, KeyExpression, SelectManyInfo);
9191

9292
var newItemProjector = ProjectionExpression.ItemProjector.RewriteApplyParameter(ApplyParameter, newApplyParameter);
93-
var newProjectionExpression = new ProjectionExpression(
94-
ProjectionExpression.Type,
95-
newItemProjector,
96-
ProjectionExpression.TupleParameterBindings,
97-
ProjectionExpression.ResultAccessMethod);
93+
var newProjectionExpression = ProjectionExpression.Apply(newItemProjector);
9894
return new GroupingExpression(Type, OuterParameter, DefaultIfEmpty, newProjectionExpression, newApplyParameter, KeyExpression, SelectManyInfo);
9995
}
10096

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2008-2020 Xtensive LLC.
1+
// Copyright (C) 2008-2021 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Alexey Kochetov
@@ -13,40 +13,29 @@ namespace Xtensive.Orm.Linq.Expressions
1313
{
1414
internal class ProjectionExpression : ExtendedExpression
1515
{
16-
public ItemProjectorExpression ItemProjector { get; private set;}
17-
public ResultAccessMethod ResultAccessMethod { get; private set; }
18-
public Dictionary<Parameter<Tuple>, Tuple> TupleParameterBindings { get; private set; }
16+
public ItemProjectorExpression ItemProjector { get; }
17+
public ResultAccessMethod ResultAccessMethod { get; }
18+
public IReadOnlyDictionary<Parameter<Tuple>, Tuple> TupleParameterBindings { get; }
1919

20-
public bool IsScalar
21-
{
22-
get { return ResultAccessMethod != ResultAccessMethod.All; }
23-
}
20+
public bool IsScalar => ResultAccessMethod != ResultAccessMethod.All;
2421

25-
public override string ToString()
26-
{
27-
return $"Projection: {ItemProjector}, IsScalar = {IsScalar}";
28-
}
22+
public override string ToString() => $"Projection: {ItemProjector}, IsScalar = {IsScalar}";
2923

24+
public ProjectionExpression Apply(ItemProjectorExpression itemProjectorExpression) =>
25+
new ProjectionExpression(Type, itemProjectorExpression, TupleParameterBindings, ResultAccessMethod);
3026

3127
// Constructors
3228

3329
public ProjectionExpression(
3430
Type type,
3531
ItemProjectorExpression itemProjectorExpression,
36-
IReadOnlyDictionary<Parameter<Tuple>, Tuple> tupleParameterBindings)
37-
: this(type, itemProjectorExpression, tupleParameterBindings, ResultAccessMethod.All)
38-
{}
39-
40-
public ProjectionExpression(
41-
Type type,
42-
ItemProjectorExpression itemProjectorExpression,
43-
IReadOnlyDictionary<Parameter<Tuple>, Tuple> tupleParameterBindings,
44-
ResultAccessMethod resultAccessMethod)
32+
IReadOnlyDictionary<Parameter<Tuple>, Tuple> tupleParameterBindings,
33+
ResultAccessMethod resultAccessMethod = ResultAccessMethod.All)
4534
: base(ExtendedExpressionType.Projection, type)
4635
{
4736
ItemProjector = itemProjectorExpression;
4837
ResultAccessMethod = resultAccessMethod;
49-
TupleParameterBindings = new Dictionary<Parameter<Tuple>, Tuple>(tupleParameterBindings);
38+
TupleParameterBindings = tupleParameterBindings;
5039
}
5140
}
52-
}
41+
}

Orm/Xtensive.Orm/Orm/Linq/Expressions/SubQueryExpression.cs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2009-2020 Xtensive LLC.
1+
// Copyright (C) 2009-2021 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Alexey Gamzov
@@ -19,9 +19,9 @@ namespace Xtensive.Orm.Linq.Expressions
1919
internal class SubQueryExpression : ParameterizedExpression,
2020
IMappedExpression
2121
{
22-
public ProjectionExpression ProjectionExpression { get; private set; }
22+
public ProjectionExpression ProjectionExpression { get; }
2323

24-
public ApplyParameter ApplyParameter { get; private set; }
24+
public ApplyParameter ApplyParameter { get; }
2525

2626
public virtual Expression BindParameter(ParameterExpression parameter, Dictionary<Expression, Expression> processedExpressions)
2727
{
@@ -105,15 +105,11 @@ public virtual Expression Remap(IReadOnlyList<int> map, Dictionary<Expression, E
105105

106106
public virtual Expression ReplaceApplyParameter(ApplyParameter newApplyParameter)
107107
{
108-
if (newApplyParameter==ApplyParameter)
108+
if (newApplyParameter == ApplyParameter)
109109
return new SubQueryExpression(Type, OuterParameter, DefaultIfEmpty, ProjectionExpression, ApplyParameter);
110110

111111
var newItemProjector = ProjectionExpression.ItemProjector.RewriteApplyParameter(ApplyParameter, newApplyParameter);
112-
var newProjectionExpression = new ProjectionExpression(
113-
ProjectionExpression.Type,
114-
newItemProjector,
115-
ProjectionExpression.TupleParameterBindings,
116-
ProjectionExpression.ResultAccessMethod);
112+
var newProjectionExpression = ProjectionExpression.Apply(newItemProjector);
117113
return new SubQueryExpression(Type, OuterParameter, DefaultIfEmpty, newProjectionExpression, newApplyParameter);
118114
}
119115

Orm/Xtensive.Orm/Orm/Linq/Expressions/Visitors/ExtendedExpressionReplacer.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,11 @@ protected override Expression VisitProjectionExpression(ProjectionExpression pro
3434
{
3535
var item = Visit(projectionExpression.ItemProjector.Item);
3636
var provider = providerVisitor.VisitCompilable(projectionExpression.ItemProjector.DataSource);
37-
var providerChanged = provider!=projectionExpression.ItemProjector.DataSource;
38-
var itemChanged = item!=projectionExpression.ItemProjector.Item;
37+
var providerChanged = provider != projectionExpression.ItemProjector.DataSource;
38+
var itemChanged = item != projectionExpression.ItemProjector.Item;
3939
if (providerChanged || itemChanged) {
4040
var itemProjector = new ItemProjectorExpression(item, provider, projectionExpression.ItemProjector.Context);
41-
return new ProjectionExpression(
42-
projectionExpression.Type,
43-
itemProjector,
44-
projectionExpression.TupleParameterBindings,
45-
projectionExpression.ResultAccessMethod);
41+
return projectionExpression.Apply(itemProjector);
4642
}
4743
return projectionExpression;
4844
}

Orm/Xtensive.Orm/Orm/Linq/LinqBindingCollection.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,7 @@ public override void ReplaceBound(ParameterExpression key, ProjectionExpression
6666
if (parameter!=key) {
6767
var projection = this[parameter];
6868
var newItemProjector = projection.ItemProjector.Remap(value.ItemProjector.DataSource, 0);
69-
var newProjection = new ProjectionExpression(
70-
projection.Type,
71-
newItemProjector,
72-
projection.TupleParameterBindings,
73-
projection.ResultAccessMethod);
69+
var newProjection = projection.Apply(newItemProjector);
7470
base.ReplaceBound(parameter, newProjection);
7571
}
7672
}

Orm/Xtensive.Orm/Orm/Linq/Materialization/ExpressionMaterializer.cs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,11 @@ protected override Expression VisitSubQueryExpression(SubQueryExpression subQuer
161161

162162
private TranslatedQuery PrepareSubqueryParameters(SubQueryExpression subQueryExpression, out Parameter<Tuple> parameterOfTuple, out Type elementType, out ProjectionExpression projection)
163163
{
164+
var projectionExpression = subQueryExpression.ProjectionExpression;
165+
164166
// 1. Rewrite recordset and ItemProjector to parameter<tuple>
165167
var subqueryTupleParameter = context.GetTupleParameter(subQueryExpression.OuterParameter);
166-
var dataSource = subQueryExpression.ProjectionExpression.ItemProjector.DataSource;
168+
var dataSource = projectionExpression.ItemProjector.DataSource;
167169

168170
var rootTags = context.GetAllTags();
169171
if (rootTags.Count > 0) {
@@ -176,27 +178,20 @@ private TranslatedQuery PrepareSubqueryParameters(SubQueryExpression subQueryExp
176178
subQueryExpression.ApplyParameter);
177179

178180
var newItemProjectorBody = ApplyParameterToTupleParameterRewriter.Rewrite(
179-
subQueryExpression.ProjectionExpression.ItemProjector.Item,
181+
projectionExpression.ItemProjector.Item,
180182
subqueryTupleParameter,
181183
subQueryExpression.ApplyParameter);
182184

183-
var itemProjector = new ItemProjectorExpression(newItemProjectorBody, newDataSource, subQueryExpression.ProjectionExpression.ItemProjector.Context);
185+
var itemProjector = new ItemProjectorExpression(newItemProjectorBody, newDataSource, projectionExpression.ItemProjector.Context);
184186
parameterOfTuple = context.GetTupleParameter(subQueryExpression.OuterParameter);
185187

186188
// 2. Add only parameter<tuple>. Tuple value will be assigned
187189
// at the moment of materialization in SubQuery constructor
188-
projection = new ProjectionExpression(
189-
subQueryExpression.ProjectionExpression.Type,
190-
itemProjector,
191-
subQueryExpression.ProjectionExpression.TupleParameterBindings,
192-
subQueryExpression.ProjectionExpression.ResultAccessMethod);
193-
194-
// 3. Make translation
195-
elementType = subQueryExpression.ProjectionExpression.ItemProjector.Item.Type;
196-
var translateMethod = Translator.TranslateMethod;
197-
return (TranslatedQuery) translateMethod.Invoke(
198-
context.Translator,
199-
new object[] {projection, tupleParameters.Append(parameterOfTuple)});
190+
projection = projectionExpression.Apply(itemProjector);
191+
192+
// 3. Make translation
193+
elementType = projectionExpression.ItemProjector.Item.Type;
194+
return context.Translator.Translate(projection, tupleParameters.Append(parameterOfTuple));
200195
}
201196

202197
protected override Expression VisitFieldExpression(FieldExpression expression)

Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterRewriter.cs

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2009-2020 Xtensive LLC.
1+
// Copyright (C) 2009-2021 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Alexey Gamzov
@@ -40,18 +40,15 @@ protected override Expression VisitMemberAccess(MemberExpression m)
4040

4141
protected override Expression VisitGroupingExpression(GroupingExpression expression)
4242
{
43-
var newProvider = Rewrite(expression.ProjectionExpression.ItemProjector.DataSource, oldApplyParameter, newApplyParameter);
44-
var newItemProjectorBody = Visit(expression.ProjectionExpression.ItemProjector.Item);
43+
var projectionExpression = expression.ProjectionExpression;
44+
var newProvider = Rewrite(projectionExpression.ItemProjector.DataSource, oldApplyParameter, newApplyParameter);
45+
var newItemProjectorBody = Visit(projectionExpression.ItemProjector.Item);
4546
var newKeyExpression = Visit(expression.KeyExpression);
46-
if (newProvider!=expression.ProjectionExpression.ItemProjector.DataSource
47-
|| newItemProjectorBody!=expression.ProjectionExpression.ItemProjector.Item
48-
|| newKeyExpression!=expression.KeyExpression) {
49-
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, expression.ProjectionExpression.ItemProjector.Context);
50-
var newProjectionExpression = new ProjectionExpression(
51-
expression.ProjectionExpression.Type,
52-
newItemProjector,
53-
expression.ProjectionExpression.TupleParameterBindings,
54-
expression.ProjectionExpression.ResultAccessMethod);
47+
if (newProvider != projectionExpression.ItemProjector.DataSource
48+
|| newItemProjectorBody != projectionExpression.ItemProjector.Item
49+
|| newKeyExpression != expression.KeyExpression) {
50+
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, projectionExpression.ItemProjector.Context);
51+
var newProjectionExpression = projectionExpression.Apply(newItemProjector);
5552
return new GroupingExpression(
5653
expression.Type, expression.OuterParameter, expression.DefaultIfEmpty, newProjectionExpression,
5754
expression.ApplyParameter, expression.KeyExpression, expression.SelectManyInfo);
@@ -61,17 +58,14 @@ protected override Expression VisitGroupingExpression(GroupingExpression express
6158

6259
protected override Expression VisitSubQueryExpression(SubQueryExpression expression)
6360
{
64-
var newProvider = Rewrite(expression.ProjectionExpression.ItemProjector.DataSource, oldApplyParameter, newApplyParameter);
65-
var newItemProjectorBody = Visit(expression.ProjectionExpression.ItemProjector.Item);
66-
if (newProvider!=expression.ProjectionExpression.ItemProjector.DataSource
67-
|| newItemProjectorBody!=expression.ProjectionExpression.ItemProjector.Item) {
61+
var projectionExpression = expression.ProjectionExpression;
62+
var newProvider = Rewrite(projectionExpression.ItemProjector.DataSource, oldApplyParameter, newApplyParameter);
63+
var newItemProjectorBody = Visit(projectionExpression.ItemProjector.Item);
64+
if (newProvider != projectionExpression.ItemProjector.DataSource
65+
|| newItemProjectorBody != projectionExpression.ItemProjector.Item) {
6866
var newItemProjector = new ItemProjectorExpression(
69-
newItemProjectorBody, newProvider, expression.ProjectionExpression.ItemProjector.Context);
70-
var newProjectionExpression = new ProjectionExpression(
71-
expression.ProjectionExpression.Type,
72-
newItemProjector,
73-
expression.ProjectionExpression.TupleParameterBindings,
74-
expression.ProjectionExpression.ResultAccessMethod);
67+
newItemProjectorBody, newProvider, projectionExpression.ItemProjector.Context);
68+
var newProjectionExpression = projectionExpression.Apply(newItemProjector);
7569
return new SubQueryExpression(
7670
expression.Type, expression.OuterParameter, expression.DefaultIfEmpty, newProjectionExpression,
7771
expression.ApplyParameter, expression.ExtendedType);

Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterToTupleParameterRewriter.cs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,15 @@ protected override Expression VisitMemberAccess(MemberExpression m)
4141

4242
protected override Expression VisitGroupingExpression(GroupingExpression expression)
4343
{
44-
var newProvider = Rewrite(expression.ProjectionExpression.ItemProjector.DataSource, parameterOfTuple, applyParameter);
45-
var newItemProjectorBody = Visit(expression.ProjectionExpression.ItemProjector.Item);
44+
var projectionExpression = expression.ProjectionExpression;
45+
var newProvider = Rewrite(projectionExpression.ItemProjector.DataSource, parameterOfTuple, applyParameter);
46+
var newItemProjectorBody = Visit(projectionExpression.ItemProjector.Item);
4647
var newKeyExpression = Visit(expression.KeyExpression);
47-
if (newProvider!=expression.ProjectionExpression.ItemProjector.DataSource
48-
|| newItemProjectorBody!=expression.ProjectionExpression.ItemProjector.Item
49-
|| newKeyExpression!=expression.KeyExpression) {
50-
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, expression.ProjectionExpression.ItemProjector.Context);
51-
var newProjectionExpression = new ProjectionExpression(
52-
expression.ProjectionExpression.Type,
53-
newItemProjector,
54-
expression.ProjectionExpression.TupleParameterBindings,
55-
expression.ProjectionExpression.ResultAccessMethod);
48+
if (newProvider != projectionExpression.ItemProjector.DataSource
49+
|| newItemProjectorBody != projectionExpression.ItemProjector.Item
50+
|| newKeyExpression != expression.KeyExpression) {
51+
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, projectionExpression.ItemProjector.Context);
52+
var newProjectionExpression = projectionExpression.Apply(newItemProjector);
5653
return new GroupingExpression(
5754
expression.Type, expression.OuterParameter, expression.DefaultIfEmpty,
5855
newProjectionExpression, expression.ApplyParameter,
@@ -63,15 +60,12 @@ protected override Expression VisitGroupingExpression(GroupingExpression express
6360

6461
protected override Expression VisitSubQueryExpression(SubQueryExpression expression)
6562
{
66-
var newProvider = Rewrite(expression.ProjectionExpression.ItemProjector.DataSource, parameterOfTuple, applyParameter);
67-
var newItemProjectorBody = Visit(expression.ProjectionExpression.ItemProjector.Item);
68-
if (newProvider!=expression.ProjectionExpression.ItemProjector.DataSource || newItemProjectorBody!=expression.ProjectionExpression.ItemProjector.Item) {
69-
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, expression.ProjectionExpression.ItemProjector.Context);
70-
var newProjectionExpression = new ProjectionExpression(
71-
expression.ProjectionExpression.Type,
72-
newItemProjector,
73-
expression.ProjectionExpression.TupleParameterBindings,
74-
expression.ProjectionExpression.ResultAccessMethod);
63+
var projectionExpression = expression.ProjectionExpression;
64+
var newProvider = Rewrite(projectionExpression.ItemProjector.DataSource, parameterOfTuple, applyParameter);
65+
var newItemProjectorBody = Visit(projectionExpression.ItemProjector.Item);
66+
if (newProvider != projectionExpression.ItemProjector.DataSource || newItemProjectorBody != projectionExpression.ItemProjector.Item) {
67+
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, projectionExpression.ItemProjector.Context);
68+
var newProjectionExpression = projectionExpression.Apply(newItemProjector);
7569
return new SubQueryExpression(
7670
expression.Type, expression.OuterParameter,
7771
expression.DefaultIfEmpty, newProjectionExpression,

0 commit comments

Comments
 (0)