From fbf6707fbdae7889380e39029f90f22816c93465 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 12 Oct 2021 14:47:42 -0700 Subject: [PATCH 1/6] Refactor & optimize ProjectionExpression, TranslatedQuery (#40) * Refactor & optimize ProjectionExpression, TranslatedQuery * EOL at EOF * Fix Translator.TranslateMethod * Get rid of Translator.TranslateMethod because we need not it for non-generic method * Rename ProjectionExpression.Select() -> .Apply() * Avoid list allocation when calling Translator.Translate() --- Orm/Xtensive.Orm/Core/ParameterContext.cs | 12 +++- Orm/Xtensive.Orm/Orm/DelayedQuery.cs | 5 +- .../Linq/Expressions/GroupingExpression.cs | 6 +- .../Linq/Expressions/ProjectionExpression.cs | 38 ++++------ .../Linq/Expressions/SubQueryExpression.cs | 14 ++-- .../Visitors/ExtendedExpressionReplacer.cs | 10 +-- .../Orm/Linq/LinqBindingCollection.cs | 6 +- .../Materialization/ExpressionMaterializer.cs | 21 +++--- .../Linq/Rewriters/ApplyParameterRewriter.cs | 38 +++++----- .../ApplyParameterToTupleParameterRewriter.cs | 34 ++++----- Orm/Xtensive.Orm/Orm/Linq/SubQuery.cs | 14 ++-- Orm/Xtensive.Orm/Orm/Linq/TranslatedQuery.cs | 29 ++++---- .../Orm/Linq/Translator.Expressions.cs | 8 +-- .../Orm/Linq/Translator.Materialization.cs | 71 +++++++------------ .../Orm/Linq/Translator.Queryable.cs | 60 ++++------------ 15 files changed, 135 insertions(+), 231 deletions(-) diff --git a/Orm/Xtensive.Orm/Core/ParameterContext.cs b/Orm/Xtensive.Orm/Core/ParameterContext.cs index add4290d48..2829d67eed 100644 --- a/Orm/Xtensive.Orm/Core/ParameterContext.cs +++ b/Orm/Xtensive.Orm/Core/ParameterContext.cs @@ -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 @@ -7,7 +7,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; - +using Tuple = Xtensive.Tuples.Tuple; namespace Xtensive.Core { @@ -42,9 +42,15 @@ public TValue GetValue(Parameter parameter) /// /// Initializes new instance of this type. /// - public ParameterContext(ParameterContext outerContext = null) + public ParameterContext(ParameterContext outerContext = null, IReadOnlyDictionary, Tuple> tupleParameterBindings = null) { this.outerContext = outerContext; + + if (tupleParameterBindings != null) { + foreach (var (parameter, tuple) in tupleParameterBindings) { + SetValue(parameter, tuple); + } + } } } } diff --git a/Orm/Xtensive.Orm/Orm/DelayedQuery.cs b/Orm/Xtensive.Orm/Orm/DelayedQuery.cs index 7bfccd8da1..b77e2db2c4 100644 --- a/Orm/Xtensive.Orm/Orm/DelayedQuery.cs +++ b/Orm/Xtensive.Orm/Orm/DelayedQuery.cs @@ -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); } diff --git a/Orm/Xtensive.Orm/Orm/Linq/Expressions/GroupingExpression.cs b/Orm/Xtensive.Orm/Orm/Linq/Expressions/GroupingExpression.cs index 4ee143f7f8..47ae5108be 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Expressions/GroupingExpression.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Expressions/GroupingExpression.cs @@ -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); } diff --git a/Orm/Xtensive.Orm/Orm/Linq/Expressions/ProjectionExpression.cs b/Orm/Xtensive.Orm/Orm/Linq/Expressions/ProjectionExpression.cs index b9d00fc9a6..1b7426307a 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Expressions/ProjectionExpression.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Expressions/ProjectionExpression.cs @@ -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 @@ -13,40 +13,30 @@ namespace Xtensive.Orm.Linq.Expressions { internal class ProjectionExpression : ExtendedExpression { - public ItemProjectorExpression ItemProjector { get; private set;} - public ResultAccessMethod ResultAccessMethod { get; private set; } - public Dictionary, Tuple> TupleParameterBindings { get; private set; } + public ItemProjectorExpression ItemProjector { get; } + public ResultAccessMethod ResultAccessMethod { get; } + public IReadOnlyDictionary, 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}"; + // Creates new ItemProjectorExpression, based on this but with new ItemProjectorExpression + public ProjectionExpression Apply(ItemProjectorExpression itemProjectorExpression) => + new ProjectionExpression(Type, itemProjectorExpression, TupleParameterBindings, ResultAccessMethod); // Constructors - public ProjectionExpression( - Type type, - ItemProjectorExpression itemProjectorExpression, - Dictionary, Tuple> tupleParameterBindings) - : this(type, itemProjectorExpression, tupleParameterBindings, ResultAccessMethod.All) - {} - public ProjectionExpression( Type type, - ItemProjectorExpression itemProjectorExpression, - Dictionary, Tuple> tupleParameterBindings, - ResultAccessMethod resultAccessMethod) + ItemProjectorExpression itemProjectorExpression, + IReadOnlyDictionary, Tuple> tupleParameterBindings, + ResultAccessMethod resultAccessMethod = ResultAccessMethod.All) : base(ExtendedExpressionType.Projection, type) { ItemProjector = itemProjectorExpression; ResultAccessMethod = resultAccessMethod; - TupleParameterBindings = new Dictionary, Tuple>(tupleParameterBindings); + TupleParameterBindings = tupleParameterBindings; } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Linq/Expressions/SubQueryExpression.cs b/Orm/Xtensive.Orm/Orm/Linq/Expressions/SubQueryExpression.cs index 6053e839bd..70a94c1c6e 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Expressions/SubQueryExpression.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Expressions/SubQueryExpression.cs @@ -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 @@ -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 processedExpressions) { @@ -105,15 +105,11 @@ public virtual Expression Remap(int[] map, Dictionary pr 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); } diff --git a/Orm/Xtensive.Orm/Orm/Linq/Expressions/Visitors/ExtendedExpressionReplacer.cs b/Orm/Xtensive.Orm/Orm/Linq/Expressions/Visitors/ExtendedExpressionReplacer.cs index 08a668cc87..d392cebba7 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Expressions/Visitors/ExtendedExpressionReplacer.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Expressions/Visitors/ExtendedExpressionReplacer.cs @@ -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; } diff --git a/Orm/Xtensive.Orm/Orm/Linq/LinqBindingCollection.cs b/Orm/Xtensive.Orm/Orm/Linq/LinqBindingCollection.cs index f2416a4875..17baecb416 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/LinqBindingCollection.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/LinqBindingCollection.cs @@ -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); } } diff --git a/Orm/Xtensive.Orm/Orm/Linq/Materialization/ExpressionMaterializer.cs b/Orm/Xtensive.Orm/Orm/Linq/Materialization/ExpressionMaterializer.cs index e76b9052ec..2711c050f2 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Materialization/ExpressionMaterializer.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Materialization/ExpressionMaterializer.cs @@ -160,35 +160,30 @@ protected override Expression VisitSubQueryExpression(SubQueryExpression subQuer private TranslatedQuery PrepareSubqueryParameters(SubQueryExpression subQueryExpression, out Parameter parameterOfTuple, out Type elementType, out ProjectionExpression projection) { + var projectionExpression = subQueryExpression.ProjectionExpression; + // 1. Rewrite recordset and ItemProjector to parameter var subqueryTupleParameter = context.GetTupleParameter(subQueryExpression.OuterParameter); var newDataSource = ApplyParameterToTupleParameterRewriter.Rewrite( - subQueryExpression.ProjectionExpression.ItemProjector.DataSource, + projectionExpression.ItemProjector.DataSource, subqueryTupleParameter, 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 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); + projection = projectionExpression.Apply(itemProjector); // 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)}); + elementType = projectionExpression.ItemProjector.Item.Type; + return context.Translator.Translate(projection, tupleParameters.Append(parameterOfTuple)); } protected override Expression VisitFieldExpression(FieldExpression expression) diff --git a/Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterRewriter.cs b/Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterRewriter.cs index 679fb90d8f..e7402d2c58 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterRewriter.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterRewriter.cs @@ -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 @@ -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); @@ -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); diff --git a/Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterToTupleParameterRewriter.cs b/Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterToTupleParameterRewriter.cs index 55e68c93e1..927960a9d8 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterToTupleParameterRewriter.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Rewriters/ApplyParameterToTupleParameterRewriter.cs @@ -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, @@ -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, diff --git a/Orm/Xtensive.Orm/Orm/Linq/SubQuery.cs b/Orm/Xtensive.Orm/Orm/Linq/SubQuery.cs index 1fcb3e60fd..32da8bd58c 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/SubQuery.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/SubQuery.cs @@ -20,8 +20,8 @@ namespace Xtensive.Orm.Linq { [Serializable] - internal class SubQuery : - IOrderedQueryable, + internal class SubQuery : + IOrderedQueryable, IOrderedEnumerable { private readonly ProjectionExpression projectionExpression; @@ -63,7 +63,7 @@ public IQueryProvider Provider private void MaterializeSelf() { - if (materializedSequence != null) + if (materializedSequence != null) return; materializedSequence = delayedQuery.ToList(); delayedQuery = null; @@ -91,16 +91,16 @@ public SubQuery(ProjectionExpression projectionExpression, TranslatedQuery query } this.projectionExpression = new ProjectionExpression( - projectionExpression.Type, - projectionExpression.ItemProjector, - tupleParameterBindings, + projectionExpression.Type, + projectionExpression.ItemProjector, + tupleParameterBindings, projectionExpression.ResultAccessMethod); var translatedQuery = new TranslatedQuery( query.DataSource, query.Materializer, query.ResultAccessMethod, tupleParameterBindings, - EnumerableUtils>.Empty); + Array.Empty>()); delayedQuery = new DelayedQuery(context.Session, translatedQuery, parameterContext); context.Session.RegisterUserDefinedDelayedQuery(delayedQuery.Task); context.MaterializationContext.MaterializationQueue.Enqueue(MaterializeSelf); diff --git a/Orm/Xtensive.Orm/Orm/Linq/TranslatedQuery.cs b/Orm/Xtensive.Orm/Orm/Linq/TranslatedQuery.cs index 9d4e5b1213..ff2b72524c 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/TranslatedQuery.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/TranslatedQuery.cs @@ -1,9 +1,10 @@ -// 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: Alexis Kochetov // Created: 2009.05.27 +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -21,6 +22,8 @@ namespace Xtensive.Orm.Linq /// internal class TranslatedQuery { + public static IReadOnlyDictionary, Tuple> EmptyTupleParameterBindings { get; } = new Dictionary, Tuple>(); + internal readonly ResultAccessMethod ResultAccessMethod; /// @@ -38,12 +41,12 @@ internal class TranslatedQuery /// /// Gets the tuple parameter bindings. /// - public Dictionary, Tuple> TupleParameterBindings { get; private set; } + public IReadOnlyDictionary, Tuple> TupleParameterBindings { get; } /// /// Gets the tuple parameters. /// - public List> TupleParameters { get; private set; } + public IEnumerable> TupleParameters { get; } /// /// Executes the query in specified parameter context. @@ -65,10 +68,7 @@ public TResult ExecuteScalar(Session session, ParameterContext paramete /// Query execution result. public QueryResult ExecuteSequence(Session session, ParameterContext parameterContext) { - var newParameterContext = new ParameterContext(parameterContext); - foreach (var (parameter, tuple) in TupleParameterBindings) { - newParameterContext.SetValue(parameter, tuple); - } + var newParameterContext = new ParameterContext(parameterContext, TupleParameterBindings); var recordSetReader = DataSource.GetRecordSetReader(session, newParameterContext); return Materializer.Invoke(recordSetReader, session, newParameterContext); } @@ -101,10 +101,7 @@ public async Task ExecuteScalarAsync( public async Task> ExecuteSequenceAsync( Session session, ParameterContext parameterContext, CancellationToken token) { - var newParameterContext = new ParameterContext(parameterContext); - foreach (var (parameter, tuple) in TupleParameterBindings) { - newParameterContext.SetValue(parameter, tuple); - } + var newParameterContext = new ParameterContext(parameterContext, TupleParameterBindings); var recordSetReader = await DataSource.GetRecordSetReaderAsync(session, newParameterContext, token).ConfigureAwait(false); return Materializer.Invoke(recordSetReader, session, newParameterContext); @@ -120,7 +117,7 @@ public async Task> ExecuteSequenceAsync( /// The materializer. /// The value describing how it is supposed to access query result. public TranslatedQuery(ExecutableProvider dataSource, Materializer materializer, ResultAccessMethod resultAccessMethod) - : this(dataSource, materializer, resultAccessMethod, new Dictionary, Tuple>(), Enumerable.Empty>()) + : this(dataSource, materializer, resultAccessMethod, EmptyTupleParameterBindings, Array.Empty>()) { } @@ -135,13 +132,13 @@ public TranslatedQuery(ExecutableProvider dataSource, Materializer materializer, public TranslatedQuery(ExecutableProvider dataSource, Materializer materializer, ResultAccessMethod resultAccessMethod, - Dictionary, Tuple> tupleParameterBindings, IEnumerable> tupleParameters) + IReadOnlyDictionary, Tuple> tupleParameterBindings, IEnumerable> tupleParameters) { DataSource = dataSource; Materializer = materializer; ResultAccessMethod = resultAccessMethod; - TupleParameterBindings = new Dictionary, Tuple>(tupleParameterBindings); - TupleParameters = tupleParameters.ToList(); + TupleParameterBindings = tupleParameterBindings; + TupleParameters = tupleParameters; } } -} \ No newline at end of file +} diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs index 4a63599bed..5b78a05075 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs @@ -503,7 +503,7 @@ private Expression ConstructFreeTextQueryRoot(Type elementType, System.Collectio rankExpression = ColumnExpression.Create(WellKnownTypes.Double, dataSource.Header.Columns.Count - 1); freeTextExpression = new FullTextExpression(fullTextIndex, entityExpression, rankExpression, null); itemProjector = new ItemProjectorExpression(freeTextExpression, dataSource, context); - return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, new Dictionary, Tuple>()); + return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, TranslatedQuery.EmptyTupleParameterBindings); } private Expression ConstructContainsTableQueryRoot(Type elementType, System.Collections.ObjectModel.ReadOnlyCollection parameters) @@ -569,7 +569,7 @@ private Expression ConstructContainsTableQueryRoot(Type elementType, System.Coll rankExpression = ColumnExpression.Create(WellKnownTypes.Double, dataSource.Header.Columns.Count - 1); freeTextExpression = new FullTextExpression(fullTextIndex, entityExpression, rankExpression, null); itemProjector = new ItemProjectorExpression(freeTextExpression, dataSource, context); - return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, new Dictionary, Tuple>()); + return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, TranslatedQuery.EmptyTupleParameterBindings); } /// InvalidOperationException. @@ -1157,7 +1157,7 @@ private Expression ConstructQueryable(MethodCallExpression mc) var index = type.Indexes.PrimaryIndex; var entityExpression = EntityExpression.Create(type, 0, false); var itemProjector = new ItemProjectorExpression(entityExpression, index.GetQuery(), context); - return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, new Dictionary, Tuple>()); + return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, TranslatedQuery.EmptyTupleParameterBindings); } private Expression BuildSubqueryResult(ProjectionExpression subQuery, Type resultType) @@ -1552,7 +1552,7 @@ private static ProjectionExpression CreateLocalCollectionProjectionExpression(Ty var itemProjector = new ItemProjectorExpression(itemToTupleConverter.Expression, recordset, translator.context); if (translator.State.JoinLocalCollectionEntity) itemProjector = EntityExpressionJoiner.JoinEntities(translator, itemProjector); - return new ProjectionExpression(itemType, itemProjector, new Dictionary, Tuple>()); + return new ProjectionExpression(itemType, itemProjector, TranslatedQuery.EmptyTupleParameterBindings); } private Expression BuildInterfaceExpression(MemberExpression ma) diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs index 27ae795a42..fb2975739a 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs @@ -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: Alexis Kochetov @@ -23,29 +23,32 @@ namespace Xtensive.Orm.Linq { internal sealed partial class Translator { + private static readonly MethodInfo VisitLocalCollectionSequenceMethod = typeof(Translator).GetMethod(nameof(VisitLocalCollectionSequence), + BindingFlags.NonPublic | BindingFlags.Instance, + new[] { "TItem" }, + new object[] { WellKnownTypes.Expression }); + + private static readonly ParameterExpression parameterContext = Expression.Parameter(WellKnownOrmTypes.ParameterContext, "parameterContext"); + private static readonly ParameterExpression tupleReader = Expression.Parameter(typeof(RecordSetReader), "tupleReader"); + private static readonly ParameterExpression session = Expression.Parameter(typeof(Session), "session"); + private readonly CompiledQueryProcessingScope compiledQueryScope; - public static readonly MethodInfo TranslateMethod; - private static readonly MethodInfo VisitLocalCollectionSequenceMethod; public TranslatedQuery Translate() { var projection = (ProjectionExpression) Visit(context.Query); - return Translate(projection, Enumerable.Empty>()); + return Translate(projection, Array.Empty>()); } - private TranslatedQuery Translate(ProjectionExpression projection, + internal TranslatedQuery Translate(ProjectionExpression projection, IEnumerable> tupleParameterBindings) { var newItemProjector = projection.ItemProjector.EnsureEntityIsJoined(); - var result = new ProjectionExpression( - projection.Type, - newItemProjector, - projection.TupleParameterBindings, - projection.ResultAccessMethod); + var result = projection.Apply(newItemProjector); var optimized = Optimize(result); // Prepare cached query, if required - var prepared = compiledQueryScope!=null + var prepared = compiledQueryScope != null ? PrepareCachedQuery(optimized, compiledQueryScope) : optimized; @@ -60,7 +63,7 @@ private TranslatedQuery Translate(ProjectionExpression projection, projection.TupleParameterBindings, tupleParameterBindings); // Providing the result to caching layer, if required - if (compiledQueryScope != null && translatedQuery.TupleParameters.Count == 0) { + if (compiledQueryScope != null && !translatedQuery.TupleParameters.Any()) { var parameterizedQuery = new ParameterizedQuery( translatedQuery, compiledQueryScope.QueryParameter); @@ -79,16 +82,13 @@ private static ProjectionExpression Optimize(ProjectionExpression origin) .GetColumns(ColumnExtractionModes.KeepSegment | ColumnExtractionModes.KeepTypeId | ColumnExtractionModes.OmitLazyLoad) .ToList(); - if (usedColumns.Count==0) + if (usedColumns.Count == 0) usedColumns.Add(0); if (usedColumns.Count < origin.ItemProjector.DataSource.Header.Length) { - var resultProvider = new SelectProvider(originProvider, usedColumns.ToArray()); - var itemProjector = origin.ItemProjector.Remap(resultProvider, usedColumns.ToArray()); - var result = new ProjectionExpression( - origin.Type, - itemProjector, - origin.TupleParameterBindings, - origin.ResultAccessMethod); + var usedColumnsArray = usedColumns.ToArray(); + var resultProvider = new SelectProvider(originProvider, usedColumnsArray); + var itemProjector = origin.ItemProjector.Remap(resultProvider, usedColumnsArray); + var result = origin.Apply(itemProjector); return result; } return origin; @@ -97,7 +97,7 @@ private static ProjectionExpression Optimize(ProjectionExpression origin) private static ProjectionExpression PrepareCachedQuery( ProjectionExpression origin, CompiledQueryProcessingScope compiledQueryScope) { - if (compiledQueryScope.QueryParameter!=null) { + if (compiledQueryScope.QueryParameter != null) { var result = compiledQueryScope.QueryParameterReplacer.Replace(origin); return (ProjectionExpression) result; } @@ -122,7 +122,7 @@ private Materializer : MaterializationHelper.CreateItemMaterializerMethodInfo.MakeGenericMethod(elementType); var itemMaterializer = itemMaterializerFactoryMethod.Invoke( - null, new object[] {materializationInfo.Expression, itemProjector.AggregateType}); + null, new object[] { materializationInfo.Expression, itemProjector.AggregateType }); Expression> materializationContextCtor = (s, entityCount) => new MaterializationContext(s, entityCount); var materializationContextExpression = materializationContextCtor @@ -148,14 +148,14 @@ private List VisitNewExpressionArguments(NewExpression n) using (CreateScope(new TranslatorState(State) { CalculateExpressions = false })) { body = Visit(argument); } - body = body.IsProjection() - ? BuildSubqueryResult((ProjectionExpression) body, argument.Type) + body = body.IsProjection() + ? BuildSubqueryResult((ProjectionExpression) body, argument.Type) : ProcessProjectionElement(body); arguments.Add(body); } var constructorParameters = n.GetConstructorParameters(); for (int i = 0; i < arguments.Count; i++) { - if (arguments[i].Type!=constructorParameters[i].ParameterType) + if (arguments[i].Type != constructorParameters[i].ParameterType) arguments[i] = Expression.Convert(arguments[i], constructorParameters[i].ParameterType); } return arguments; @@ -163,7 +163,7 @@ private List VisitNewExpressionArguments(NewExpression n) private ProjectionExpression GetIndexBinding(LambdaExpression le, ref ProjectionExpression sequence) { - if (le.Parameters.Count==2) { + if (le.Parameters.Count == 2) { var indexDataSource = sequence.ItemProjector.DataSource.RowNumber(context.GetNextColumnAlias()); var columnExpression = ColumnExpression.Create(WellKnownTypes.Int64, indexDataSource.Header.Columns.Count - 1); var indexExpression = Expression.Subtract(columnExpression, Expression.Constant(1L)); @@ -171,11 +171,7 @@ private ProjectionExpression GetIndexBinding(LambdaExpression le, ref Projection var indexItemProjector = new ItemProjectorExpression(itemExpression, indexDataSource, context); var indexProjectionExpression = new ProjectionExpression(WellKnownTypes.Int64, indexItemProjector, sequence.TupleParameterBindings); var sequenceItemProjector = sequence.ItemProjector.Remap(indexDataSource, 0); - sequence = new ProjectionExpression( - sequence.Type, - sequenceItemProjector, - sequence.TupleParameterBindings, - sequence.ResultAccessMethod); + sequence = sequence.Apply(sequenceItemProjector); return indexProjectionExpression; } return null; @@ -203,18 +199,5 @@ internal Translator(TranslatorContext context, CompiledQueryProcessingScope comp this.compiledQueryScope = compiledQueryScope; this.context = context; } - - static Translator() - { - TranslateMethod = typeof(Translator).GetMethod(nameof(Translate), - BindingFlags.NonPublic | BindingFlags.Instance, - Array.Empty(), - new object[] {WellKnownOrmTypes.ProjectionExpression, typeof(IEnumerable>)}); - - VisitLocalCollectionSequenceMethod = typeof(Translator).GetMethod(nameof(VisitLocalCollectionSequence), - BindingFlags.NonPublic | BindingFlags.Instance, - new[] {"TItem"}, - new object[] {WellKnownTypes.Expression}); - } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs index f349680888..c2a7b7f013 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs @@ -259,11 +259,7 @@ private Expression VisitLock(MethodCallExpression expression) var newDataSource = visitedSource.ItemProjector.DataSource.Lock(lockMode, lockBehavior); var newItemProjector = new ItemProjectorExpression( visitedSource.ItemProjector.Item, newDataSource, visitedSource.ItemProjector.Context); - var projectionExpression = new ProjectionExpression( - visitedSource.Type, - newItemProjector, - visitedSource.TupleParameterBindings, - visitedSource.ResultAccessMethod); + var projectionExpression = visitedSource.Apply(newItemProjector); return projectionExpression; } @@ -318,8 +314,7 @@ private ProjectionExpression VisitCast(Expression source, Type targetType, Type var visitedSource = VisitSequence(source); var itemProjector = visitedSource.ItemProjector.EnsureEntityIsJoined(); - var projection = new ProjectionExpression(visitedSource.Type, itemProjector, visitedSource.TupleParameterBindings, - visitedSource.ResultAccessMethod); + var projection = visitedSource.Apply(itemProjector); if (targetType == sourceType) { return projection; } @@ -737,20 +732,14 @@ private Expression VisitAggregate(Expression source, MethodInfo method, LambdaEx commonOriginDataSource, groupingDataSource.GroupColumnIndexes, groupingDataSource.AggregateColumns.Select(c => c.Descriptor).Append(aggregateDescriptor).ToArray()); var optimizedItemProjector = groupingProjection.ItemProjector.Remap(resultDataSource, 0); - groupingProjection = new ProjectionExpression( - groupingProjection.Type, optimizedItemProjector, - groupingProjection.TupleParameterBindings, groupingProjection.ResultAccessMethod); + groupingProjection = groupingProjection.Apply(optimizedItemProjector); context.Bindings.ReplaceBound(groupingParameter, groupingProjection); var isSubqueryParameter = State.OuterParameters.Contains(groupingParameter); if (isSubqueryParameter) { var newApplyParameter = context.GetApplyParameter(resultDataSource); foreach (var innerParameter in State.Parameters) { var projectionExpression = context.Bindings[innerParameter]; - var newProjectionExpression = new ProjectionExpression( - projectionExpression.Type, - projectionExpression.ItemProjector.RewriteApplyParameter(groupingFilterParameter, newApplyParameter), - projectionExpression.TupleParameterBindings, - projectionExpression.ResultAccessMethod); + var newProjectionExpression = projectionExpression.Apply(projectionExpression.ItemProjector.RewriteApplyParameter(groupingFilterParameter, newApplyParameter)); context.Bindings.ReplaceBound(innerParameter, newProjectionExpression); } } @@ -1020,15 +1009,10 @@ private ProjectionExpression VisitGroupBy(Type returnType, Expression source, La }); var filter = FastExpression.Lambda(filterBody, tupleParameter); - var subqueryProjection = new ProjectionExpression( - sequence.Type, - new ItemProjectorExpression( + var subqueryProjection = sequence.Apply(new ItemProjectorExpression( sequence.ItemProjector.Item, groupingSourceProjection.ItemProjector.DataSource.Filter((Expression>) filter), - context), - sequence.TupleParameterBindings, - sequence.ResultAccessMethod - ); + context)); // var groupingParameter = Expression.Parameter(groupingProjection.ItemProjector.Item.Type, "groupingParameter"); // var applyParameter = context.GetApplyParameter(groupingProjection); // using (context.Bindings.Add(groupingParameter, groupingProjection)) @@ -1213,11 +1197,7 @@ private Expression VisitGroupJoin(Expression outerSource, Expression innerSource newGroupingExpression, innerGrouping.ItemProjector.DataSource, innerGrouping.ItemProjector.Context); - innerGrouping = new ProjectionExpression( - innerGrouping.Type, - newGroupingItemProjector, - innerGrouping.TupleParameterBindings, - innerGrouping.ResultAccessMethod); + innerGrouping = innerGrouping.Apply(newGroupingItemProjector); } var groupingKeyPropertyInfo = groupingType.GetProperty("Key"); @@ -1304,11 +1284,7 @@ private ProjectionExpression VisitSelectMany(Expression source, LambdaExpression innerItemProjector = innerItemProjector.SetDefaultIfEmpty(); } - innerProjection = new ProjectionExpression( - projection.Type, - innerItemProjector, - projection.TupleParameterBindings, - projection.ResultAccessMethod); + innerProjection = projection.Apply(innerItemProjector); } var outerProjection = context.Bindings[outerParameter]; @@ -1328,11 +1304,7 @@ private ProjectionExpression VisitSelectMany(Expression source, LambdaExpression var resultProjection = CombineProjections(outerProjection, innerProjection, recordSet, resultSelector); var resultItemProjector = resultProjection.ItemProjector.RemoveOuterParameter(); - resultProjection = new ProjectionExpression( - resultProjection.Type, - resultItemProjector, - resultProjection.TupleParameterBindings, - resultProjection.ResultAccessMethod); + resultProjection = resultProjection.Apply(resultItemProjector); return resultProjection; } } @@ -1362,7 +1334,7 @@ private ProjectionExpression BuildProjection(LambdaExpression le) return new ProjectionExpression( WellKnownInterfaces.QueryableOfT.MakeGenericType(le.Body.Type), itemProjector, - new Dictionary, Tuple>()); + TranslatedQuery.EmptyTupleParameterBindings); } } @@ -1497,11 +1469,7 @@ private Expression VisitExistsAsInclude(Expression source, LambdaExpression pred .Include(State.IncludeAlgorithm, true, rawProvider.Source, context.GetNextAlias(), filteredColumns); var newItemProjector = outerResult.ItemProjector.Remap(newDataSource, 0); - var newOuterResult = new ProjectionExpression( - outerResult.Type, - newItemProjector, - outerResult.TupleParameterBindings, - outerResult.ResultAccessMethod); + var newOuterResult = outerResult.Apply(newItemProjector); context.Bindings.ReplaceBound(outerParameter, newOuterResult); Expression resultExpression = ColumnExpression.Create(WellKnownTypes.Bool, columnIndex); if (notExists) { @@ -1679,11 +1647,7 @@ private ProjectionExpression VisitSequence(Expression sequenceExpression, Expres if (result != null) { var projectorExpression = result.ItemProjector.EnsureEntityIsJoined(); if (projectorExpression != result.ItemProjector) { - result = new ProjectionExpression( - result.Type, - projectorExpression, - result.TupleParameterBindings, - result.ResultAccessMethod); + result = result.Apply(projectorExpression); } return result; From 68f68735e0f1f52529a6f875bc8489eff3796457 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Wed, 3 Nov 2021 13:57:39 -0700 Subject: [PATCH 2/6] Remove misleading comment --- .../Orm/Linq/Expressions/ProjectionExpression.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Linq/Expressions/ProjectionExpression.cs b/Orm/Xtensive.Orm/Orm/Linq/Expressions/ProjectionExpression.cs index 1b7426307a..aa76d8f37b 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Expressions/ProjectionExpression.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Expressions/ProjectionExpression.cs @@ -21,16 +21,15 @@ internal class ProjectionExpression : ExtendedExpression public override string ToString() => $"Projection: {ItemProjector}, IsScalar = {IsScalar}"; - // Creates new ItemProjectorExpression, based on this but with new ItemProjectorExpression public ProjectionExpression Apply(ItemProjectorExpression itemProjectorExpression) => new ProjectionExpression(Type, itemProjectorExpression, TupleParameterBindings, ResultAccessMethod); // Constructors public ProjectionExpression( - Type type, + Type type, ItemProjectorExpression itemProjectorExpression, - IReadOnlyDictionary, Tuple> tupleParameterBindings, + IReadOnlyDictionary, Tuple> tupleParameterBindings, ResultAccessMethod resultAccessMethod = ResultAccessMethod.All) : base(ExtendedExpressionType.Projection, type) { From ea0995386e927fa227fd5b420e929fd89c5e0190 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Wed, 3 Nov 2021 14:02:51 -0700 Subject: [PATCH 3/6] Translator.EmptyTupleParameterBindings static member --- Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs index 5b78a05075..0bb6ce443c 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs @@ -33,6 +33,8 @@ namespace Xtensive.Orm.Linq { internal sealed partial class Translator { + private static IReadOnlyDictionary, Tuple> EmptyTupleParameterBindings { get; } = new Dictionary, Tuple>(); + protected override Expression VisitTypeIs(TypeBinaryExpression tb) { var expression = tb.Expression; @@ -503,7 +505,7 @@ private Expression ConstructFreeTextQueryRoot(Type elementType, System.Collectio rankExpression = ColumnExpression.Create(WellKnownTypes.Double, dataSource.Header.Columns.Count - 1); freeTextExpression = new FullTextExpression(fullTextIndex, entityExpression, rankExpression, null); itemProjector = new ItemProjectorExpression(freeTextExpression, dataSource, context); - return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, TranslatedQuery.EmptyTupleParameterBindings); + return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, EmptyTupleParameterBindings); } private Expression ConstructContainsTableQueryRoot(Type elementType, System.Collections.ObjectModel.ReadOnlyCollection parameters) @@ -569,7 +571,7 @@ private Expression ConstructContainsTableQueryRoot(Type elementType, System.Coll rankExpression = ColumnExpression.Create(WellKnownTypes.Double, dataSource.Header.Columns.Count - 1); freeTextExpression = new FullTextExpression(fullTextIndex, entityExpression, rankExpression, null); itemProjector = new ItemProjectorExpression(freeTextExpression, dataSource, context); - return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, TranslatedQuery.EmptyTupleParameterBindings); + return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, EmptyTupleParameterBindings); } /// InvalidOperationException. @@ -1157,7 +1159,7 @@ private Expression ConstructQueryable(MethodCallExpression mc) var index = type.Indexes.PrimaryIndex; var entityExpression = EntityExpression.Create(type, 0, false); var itemProjector = new ItemProjectorExpression(entityExpression, index.GetQuery(), context); - return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, TranslatedQuery.EmptyTupleParameterBindings); + return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, EmptyTupleParameterBindings); } private Expression BuildSubqueryResult(ProjectionExpression subQuery, Type resultType) From 444bddc0c3e8ba5ae21a2cd6826ae62dd04de25d Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Wed, 3 Nov 2021 14:05:58 -0700 Subject: [PATCH 4/6] Remove unnecessary immutable object creation --- Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs index fb2975739a..6931d657a5 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs @@ -107,10 +107,6 @@ private static ProjectionExpression PrepareCachedQuery( private Materializer BuildMaterializer(ProjectionExpression projection, IEnumerable> tupleParameters) { - var tupleReader = Expression.Parameter(typeof (RecordSetReader), "tupleReader"); - var session = Expression.Parameter(typeof (Session), "session"); - var parameterContext = Expression.Parameter(WellKnownOrmTypes.ParameterContext, "parameterContext"); - var itemProjector = projection.ItemProjector; var materializationInfo = itemProjector.Materialize(context, tupleParameters); var elementType = itemProjector.Item.Type; From 73de936b4957b0c4d1953eff3758972fb03b17f8 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 9 Nov 2021 18:45:21 -0800 Subject: [PATCH 5/6] Fix build --- Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs index f50f96592e..018d5073b1 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs @@ -1039,7 +1039,7 @@ private ProjectionExpression VisitGroupBy(Type returnType, Expression source, La ExpressionType.AndAlso); }); - var filter = FastExpression.Lambda(filterBody, tupleParameter); + var filter = FastExpression.Lambda(filterBody, TupleParameter); var subqueryProjection = sequence.Apply(new ItemProjectorExpression( sequence.ItemProjector.Item, groupingSourceProjection.ItemProjector.DataSource.Filter((Expression>) filter), From 463266fae5f9ebb7b7b11073f683e3bd21d237e5 Mon Sep 17 00:00:00 2001 From: Sergei Pavlov Date: Tue, 9 Nov 2021 21:02:51 -0800 Subject: [PATCH 6/6] PascalCase for static read only --- Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs index abb84e269e..b7562318f1 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs @@ -35,7 +35,7 @@ internal sealed partial class Translator { private static IReadOnlyDictionary, Tuple> EmptyTupleParameterBindings { get; } = new Dictionary, Tuple>(); - private static readonly ParameterExpression parameterContextParam = Expression.Parameter(WellKnownOrmTypes.ParameterContext, "context"); + private static readonly ParameterExpression ParameterContextParam = Expression.Parameter(WellKnownOrmTypes.ParameterContext, "context"); private static readonly ConstantExpression NullKeyExpression = Expression.Constant(null, WellKnownOrmTypes.Key), FalseExpression = Expression.Constant(false), @@ -511,7 +511,7 @@ private Expression ConstructFreeTextQueryRoot(Type elementType, System.Collectio if (compiledQueryScope==null) { var originalSearchCriteria = (Expression>) searchCriteria; var body = originalSearchCriteria.Body; - var searchCriteriaLambda = FastExpression.Lambda>(body, parameterContextParam); + var searchCriteriaLambda = FastExpression.Lambda>(body, ParameterContextParam); compiledParameter = searchCriteriaLambda.CachingCompile(); } else { @@ -578,7 +578,7 @@ private Expression ConstructContainsTableQueryRoot(Type elementType, System.Coll func.Invoke(SearchConditionNodeFactory.CreateConditonRoot()).AcceptVisitor(conditionCompiler); var preparedSearchCriteria = FastExpression.Lambda>( - Expression.Constant(conditionCompiler.CurrentOutput), parameterContextParam); + Expression.Constant(conditionCompiler.CurrentOutput), ParameterContextParam); if (compiledQueryScope==null) { compiledParameter = preparedSearchCriteria.CachingCompile();