Skip to content
12 changes: 9 additions & 3 deletions Orm/Xtensive.Orm/Core/ParameterContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2008-2020 Xtensive LLC.
// Copyright (C) 2008-2021 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
// Created by: Alex Kofman
Expand All @@ -7,7 +7,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;

using Tuple = Xtensive.Tuples.Tuple;

namespace Xtensive.Core
{
Expand Down Expand Up @@ -42,9 +42,15 @@ public TValue GetValue<TValue>(Parameter<TValue> parameter)
/// <summary>
/// Initializes new instance of this type.
/// </summary>
public ParameterContext(ParameterContext outerContext = null)
public ParameterContext(ParameterContext outerContext = null, IReadOnlyDictionary<Parameter<Tuple>, Tuple> tupleParameterBindings = null)
{
this.outerContext = outerContext;

if (tupleParameterBindings != null) {
foreach (var (parameter, tuple) in tupleParameterBindings) {
SetValue(parameter, tuple);
}
}
}
}
}
5 changes: 1 addition & 4 deletions Orm/Xtensive.Orm/Orm/DelayedQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,7 @@ internal DelayedQuery(Session session, TranslatedQuery translatedQuery, Paramete
LifetimeToken = session.GetLifetimeToken();

materializer = translatedQuery.Materializer;
parameterContext = new ParameterContext(outerParameterContext);
foreach (var (parameter, tuple) in translatedQuery.TupleParameterBindings) {
parameterContext.SetValue(parameter, tuple);
}
parameterContext = new ParameterContext(outerParameterContext, translatedQuery.TupleParameterBindings);

Task = new QueryTask(translatedQuery.DataSource, LifetimeToken, parameterContext);
}
Expand Down
6 changes: 1 addition & 5 deletions Orm/Xtensive.Orm/Orm/Linq/Expressions/GroupingExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,7 @@ public override Expression ReplaceApplyParameter(ApplyParameter newApplyParamete
return new GroupingExpression(Type, OuterParameter, DefaultIfEmpty, ProjectionExpression, ApplyParameter, KeyExpression, SelectManyInfo);

var newItemProjector = ProjectionExpression.ItemProjector.RewriteApplyParameter(ApplyParameter, newApplyParameter);
var newProjectionExpression = new ProjectionExpression(
ProjectionExpression.Type,
newItemProjector,
ProjectionExpression.TupleParameterBindings,
ProjectionExpression.ResultAccessMethod);
var newProjectionExpression = ProjectionExpression.Apply(newItemProjector);
return new GroupingExpression(Type, OuterParameter, DefaultIfEmpty, newProjectionExpression, newApplyParameter, KeyExpression, SelectManyInfo);
}

Expand Down
35 changes: 12 additions & 23 deletions Orm/Xtensive.Orm/Orm/Linq/Expressions/ProjectionExpression.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2008-2020 Xtensive LLC.
// Copyright (C) 2008-2021 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
// Created by: Alexey Kochetov
Expand All @@ -13,40 +13,29 @@ namespace Xtensive.Orm.Linq.Expressions
{
internal class ProjectionExpression : ExtendedExpression
{
public ItemProjectorExpression ItemProjector { get; private set;}
public ResultAccessMethod ResultAccessMethod { get; private set; }
public Dictionary<Parameter<Tuple>, Tuple> TupleParameterBindings { get; private set; }
public ItemProjectorExpression ItemProjector { get; }
public ResultAccessMethod ResultAccessMethod { get; }
public IReadOnlyDictionary<Parameter<Tuple>, Tuple> TupleParameterBindings { get; }

public bool IsScalar
{
get { return ResultAccessMethod != ResultAccessMethod.All; }
}
public bool IsScalar => ResultAccessMethod != ResultAccessMethod.All;

public override string ToString()
{
return $"Projection: {ItemProjector}, IsScalar = {IsScalar}";
}
public override string ToString() => $"Projection: {ItemProjector}, IsScalar = {IsScalar}";

public ProjectionExpression Apply(ItemProjectorExpression itemProjectorExpression) =>
new ProjectionExpression(Type, itemProjectorExpression, TupleParameterBindings, ResultAccessMethod);

// Constructors

public ProjectionExpression(
Type type,
ItemProjectorExpression itemProjectorExpression,
IReadOnlyDictionary<Parameter<Tuple>, Tuple> tupleParameterBindings)
: this(type, itemProjectorExpression, tupleParameterBindings, ResultAccessMethod.All)
{}

public ProjectionExpression(
Type type,
ItemProjectorExpression itemProjectorExpression,
IReadOnlyDictionary<Parameter<Tuple>, Tuple> tupleParameterBindings,
ResultAccessMethod resultAccessMethod)
IReadOnlyDictionary<Parameter<Tuple>, Tuple> tupleParameterBindings,
ResultAccessMethod resultAccessMethod = ResultAccessMethod.All)
: base(ExtendedExpressionType.Projection, type)
{
ItemProjector = itemProjectorExpression;
ResultAccessMethod = resultAccessMethod;
TupleParameterBindings = new Dictionary<Parameter<Tuple>, Tuple>(tupleParameterBindings);
TupleParameterBindings = tupleParameterBindings;
}
}
}
}
14 changes: 5 additions & 9 deletions Orm/Xtensive.Orm/Orm/Linq/Expressions/SubQueryExpression.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2009-2020 Xtensive LLC.
// Copyright (C) 2009-2021 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
// Created by: Alexey Gamzov
Expand All @@ -19,9 +19,9 @@ namespace Xtensive.Orm.Linq.Expressions
internal class SubQueryExpression : ParameterizedExpression,
IMappedExpression
{
public ProjectionExpression ProjectionExpression { get; private set; }
public ProjectionExpression ProjectionExpression { get; }

public ApplyParameter ApplyParameter { get; private set; }
public ApplyParameter ApplyParameter { get; }

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

public virtual Expression ReplaceApplyParameter(ApplyParameter newApplyParameter)
{
if (newApplyParameter==ApplyParameter)
if (newApplyParameter == ApplyParameter)
return new SubQueryExpression(Type, OuterParameter, DefaultIfEmpty, ProjectionExpression, ApplyParameter);

var newItemProjector = ProjectionExpression.ItemProjector.RewriteApplyParameter(ApplyParameter, newApplyParameter);
var newProjectionExpression = new ProjectionExpression(
ProjectionExpression.Type,
newItemProjector,
ProjectionExpression.TupleParameterBindings,
ProjectionExpression.ResultAccessMethod);
var newProjectionExpression = ProjectionExpression.Apply(newItemProjector);
return new SubQueryExpression(Type, OuterParameter, DefaultIfEmpty, newProjectionExpression, newApplyParameter);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,11 @@ protected override Expression VisitProjectionExpression(ProjectionExpression pro
{
var item = Visit(projectionExpression.ItemProjector.Item);
var provider = providerVisitor.VisitCompilable(projectionExpression.ItemProjector.DataSource);
var providerChanged = provider!=projectionExpression.ItemProjector.DataSource;
var itemChanged = item!=projectionExpression.ItemProjector.Item;
var providerChanged = provider != projectionExpression.ItemProjector.DataSource;
var itemChanged = item != projectionExpression.ItemProjector.Item;
if (providerChanged || itemChanged) {
var itemProjector = new ItemProjectorExpression(item, provider, projectionExpression.ItemProjector.Context);
return new ProjectionExpression(
projectionExpression.Type,
itemProjector,
projectionExpression.TupleParameterBindings,
projectionExpression.ResultAccessMethod);
return projectionExpression.Apply(itemProjector);
}
return projectionExpression;
}
Expand Down
6 changes: 1 addition & 5 deletions Orm/Xtensive.Orm/Orm/Linq/LinqBindingCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,7 @@ public override void ReplaceBound(ParameterExpression key, ProjectionExpression
if (parameter!=key) {
var projection = this[parameter];
var newItemProjector = projection.ItemProjector.Remap(value.ItemProjector.DataSource, 0);
var newProjection = new ProjectionExpression(
projection.Type,
newItemProjector,
projection.TupleParameterBindings,
projection.ResultAccessMethod);
var newProjection = projection.Apply(newItemProjector);
base.ReplaceBound(parameter, newProjection);
}
}
Expand Down
25 changes: 10 additions & 15 deletions Orm/Xtensive.Orm/Orm/Linq/Materialization/ExpressionMaterializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,11 @@ protected override Expression VisitSubQueryExpression(SubQueryExpression subQuer

private TranslatedQuery PrepareSubqueryParameters(SubQueryExpression subQueryExpression, out Parameter<Tuple> parameterOfTuple, out Type elementType, out ProjectionExpression projection)
{
var projectionExpression = subQueryExpression.ProjectionExpression;

// 1. Rewrite recordset and ItemProjector to parameter<tuple>
var subqueryTupleParameter = context.GetTupleParameter(subQueryExpression.OuterParameter);
var dataSource = subQueryExpression.ProjectionExpression.ItemProjector.DataSource;
var dataSource = projectionExpression.ItemProjector.DataSource;

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

var newItemProjectorBody = ApplyParameterToTupleParameterRewriter.Rewrite(
subQueryExpression.ProjectionExpression.ItemProjector.Item,
projectionExpression.ItemProjector.Item,
subqueryTupleParameter,
subQueryExpression.ApplyParameter);

var itemProjector = new ItemProjectorExpression(newItemProjectorBody, newDataSource, subQueryExpression.ProjectionExpression.ItemProjector.Context);
var itemProjector = new ItemProjectorExpression(newItemProjectorBody, newDataSource, projectionExpression.ItemProjector.Context);
parameterOfTuple = context.GetTupleParameter(subQueryExpression.OuterParameter);

// 2. Add only parameter<tuple>. Tuple value will be assigned
// at the moment of materialization in SubQuery constructor
projection = new ProjectionExpression(
subQueryExpression.ProjectionExpression.Type,
itemProjector,
subQueryExpression.ProjectionExpression.TupleParameterBindings,
subQueryExpression.ProjectionExpression.ResultAccessMethod);

// 3. Make translation
elementType = subQueryExpression.ProjectionExpression.ItemProjector.Item.Type;
var translateMethod = Translator.TranslateMethod;
return (TranslatedQuery) translateMethod.Invoke(
context.Translator,
new object[] {projection, tupleParameters.Append(parameterOfTuple)});
projection = projectionExpression.Apply(itemProjector);

// 3. Make translation
elementType = projectionExpression.ItemProjector.Item.Type;
return context.Translator.Translate(projection, tupleParameters.Append(parameterOfTuple));
}

protected override Expression VisitFieldExpression(FieldExpression expression)
Expand Down
38 changes: 16 additions & 22 deletions Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterRewriter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2009-2020 Xtensive LLC.
// Copyright (C) 2009-2021 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
// Created by: Alexey Gamzov
Expand Down Expand Up @@ -40,18 +40,15 @@ protected override Expression VisitMemberAccess(MemberExpression m)

protected override Expression VisitGroupingExpression(GroupingExpression expression)
{
var newProvider = Rewrite(expression.ProjectionExpression.ItemProjector.DataSource, oldApplyParameter, newApplyParameter);
var newItemProjectorBody = Visit(expression.ProjectionExpression.ItemProjector.Item);
var projectionExpression = expression.ProjectionExpression;
var newProvider = Rewrite(projectionExpression.ItemProjector.DataSource, oldApplyParameter, newApplyParameter);
var newItemProjectorBody = Visit(projectionExpression.ItemProjector.Item);
var newKeyExpression = Visit(expression.KeyExpression);
if (newProvider!=expression.ProjectionExpression.ItemProjector.DataSource
|| newItemProjectorBody!=expression.ProjectionExpression.ItemProjector.Item
|| newKeyExpression!=expression.KeyExpression) {
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, expression.ProjectionExpression.ItemProjector.Context);
var newProjectionExpression = new ProjectionExpression(
expression.ProjectionExpression.Type,
newItemProjector,
expression.ProjectionExpression.TupleParameterBindings,
expression.ProjectionExpression.ResultAccessMethod);
if (newProvider != projectionExpression.ItemProjector.DataSource
|| newItemProjectorBody != projectionExpression.ItemProjector.Item
|| newKeyExpression != expression.KeyExpression) {
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, projectionExpression.ItemProjector.Context);
var newProjectionExpression = projectionExpression.Apply(newItemProjector);
return new GroupingExpression(
expression.Type, expression.OuterParameter, expression.DefaultIfEmpty, newProjectionExpression,
expression.ApplyParameter, expression.KeyExpression, expression.SelectManyInfo);
Expand All @@ -61,17 +58,14 @@ protected override Expression VisitGroupingExpression(GroupingExpression express

protected override Expression VisitSubQueryExpression(SubQueryExpression expression)
{
var newProvider = Rewrite(expression.ProjectionExpression.ItemProjector.DataSource, oldApplyParameter, newApplyParameter);
var newItemProjectorBody = Visit(expression.ProjectionExpression.ItemProjector.Item);
if (newProvider!=expression.ProjectionExpression.ItemProjector.DataSource
|| newItemProjectorBody!=expression.ProjectionExpression.ItemProjector.Item) {
var projectionExpression = expression.ProjectionExpression;
var newProvider = Rewrite(projectionExpression.ItemProjector.DataSource, oldApplyParameter, newApplyParameter);
var newItemProjectorBody = Visit(projectionExpression.ItemProjector.Item);
if (newProvider != projectionExpression.ItemProjector.DataSource
|| newItemProjectorBody != projectionExpression.ItemProjector.Item) {
var newItemProjector = new ItemProjectorExpression(
newItemProjectorBody, newProvider, expression.ProjectionExpression.ItemProjector.Context);
var newProjectionExpression = new ProjectionExpression(
expression.ProjectionExpression.Type,
newItemProjector,
expression.ProjectionExpression.TupleParameterBindings,
expression.ProjectionExpression.ResultAccessMethod);
newItemProjectorBody, newProvider, projectionExpression.ItemProjector.Context);
var newProjectionExpression = projectionExpression.Apply(newItemProjector);
return new SubQueryExpression(
expression.Type, expression.OuterParameter, expression.DefaultIfEmpty, newProjectionExpression,
expression.ApplyParameter, expression.ExtendedType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,15 @@ protected override Expression VisitMemberAccess(MemberExpression m)

protected override Expression VisitGroupingExpression(GroupingExpression expression)
{
var newProvider = Rewrite(expression.ProjectionExpression.ItemProjector.DataSource, parameterOfTuple, applyParameter);
var newItemProjectorBody = Visit(expression.ProjectionExpression.ItemProjector.Item);
var projectionExpression = expression.ProjectionExpression;
var newProvider = Rewrite(projectionExpression.ItemProjector.DataSource, parameterOfTuple, applyParameter);
var newItemProjectorBody = Visit(projectionExpression.ItemProjector.Item);
var newKeyExpression = Visit(expression.KeyExpression);
if (newProvider!=expression.ProjectionExpression.ItemProjector.DataSource
|| newItemProjectorBody!=expression.ProjectionExpression.ItemProjector.Item
|| newKeyExpression!=expression.KeyExpression) {
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, expression.ProjectionExpression.ItemProjector.Context);
var newProjectionExpression = new ProjectionExpression(
expression.ProjectionExpression.Type,
newItemProjector,
expression.ProjectionExpression.TupleParameterBindings,
expression.ProjectionExpression.ResultAccessMethod);
if (newProvider != projectionExpression.ItemProjector.DataSource
|| newItemProjectorBody != projectionExpression.ItemProjector.Item
|| newKeyExpression != expression.KeyExpression) {
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, projectionExpression.ItemProjector.Context);
var newProjectionExpression = projectionExpression.Apply(newItemProjector);
return new GroupingExpression(
expression.Type, expression.OuterParameter, expression.DefaultIfEmpty,
newProjectionExpression, expression.ApplyParameter,
Expand All @@ -63,15 +60,12 @@ protected override Expression VisitGroupingExpression(GroupingExpression express

protected override Expression VisitSubQueryExpression(SubQueryExpression expression)
{
var newProvider = Rewrite(expression.ProjectionExpression.ItemProjector.DataSource, parameterOfTuple, applyParameter);
var newItemProjectorBody = Visit(expression.ProjectionExpression.ItemProjector.Item);
if (newProvider!=expression.ProjectionExpression.ItemProjector.DataSource || newItemProjectorBody!=expression.ProjectionExpression.ItemProjector.Item) {
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, expression.ProjectionExpression.ItemProjector.Context);
var newProjectionExpression = new ProjectionExpression(
expression.ProjectionExpression.Type,
newItemProjector,
expression.ProjectionExpression.TupleParameterBindings,
expression.ProjectionExpression.ResultAccessMethod);
var projectionExpression = expression.ProjectionExpression;
var newProvider = Rewrite(projectionExpression.ItemProjector.DataSource, parameterOfTuple, applyParameter);
var newItemProjectorBody = Visit(projectionExpression.ItemProjector.Item);
if (newProvider != projectionExpression.ItemProjector.DataSource || newItemProjectorBody != projectionExpression.ItemProjector.Item) {
var newItemProjector = new ItemProjectorExpression(newItemProjectorBody, newProvider, projectionExpression.ItemProjector.Context);
var newProjectionExpression = projectionExpression.Apply(newItemProjector);
return new SubQueryExpression(
expression.Type, expression.OuterParameter,
expression.DefaultIfEmpty, newProjectionExpression,
Expand Down
Loading