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 4335650600..5f9663e10f 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 114e5f6782..aa76d8f37b 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,29 @@ 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}"; + public ProjectionExpression Apply(ItemProjectorExpression itemProjectorExpression) => + new ProjectionExpression(Type, itemProjectorExpression, TupleParameterBindings, ResultAccessMethod); // Constructors public ProjectionExpression( Type type, ItemProjectorExpression itemProjectorExpression, - IReadOnlyDictionary, Tuple> tupleParameterBindings) - : this(type, itemProjectorExpression, tupleParameterBindings, ResultAccessMethod.All) - {} - - public ProjectionExpression( - Type type, - ItemProjectorExpression itemProjectorExpression, - IReadOnlyDictionary, Tuple> tupleParameterBindings, - ResultAccessMethod resultAccessMethod) + 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 288cae96ff..f34c0312e7 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(IReadOnlyList map, Dictionary 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 dataSource = subQueryExpression.ProjectionExpression.ItemProjector.DataSource; + var dataSource = projectionExpression.ItemProjector.DataSource; var rootTags = context.GetAllTags(); if (rootTags.Count > 0) { @@ -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 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) 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 52ccd5dd8c..2924f60f05 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs @@ -1598,7 +1598,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 fff58d3bdb..a41a3efe68 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs @@ -23,33 +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; @@ -64,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); @@ -83,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); - 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; @@ -101,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 +118,7 @@ private Materializer : MaterializationHelper.CreateItemMaterializerMethodInfo.CachedMakeGenericMethod(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 +144,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 +159,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 +167,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; @@ -204,18 +196,5 @@ internal Translator(TranslatorContext context, CompiledQueryProcessingScope comp this.context = context; tagsEnabled = context.Domain.Configuration.TagsLocation != TagsLocation.Nowhere; } - - 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}); - } } } diff --git a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs index 5572121965..a6e93aa11d 100644 --- a/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs +++ b/Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs @@ -262,11 +262,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; } @@ -351,8 +347,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; } @@ -769,20 +764,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); } } @@ -1051,15 +1040,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)) @@ -1244,11 +1228,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"); @@ -1336,11 +1316,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]; @@ -1360,11 +1336,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; } } @@ -1394,7 +1366,7 @@ private ProjectionExpression BuildProjection(LambdaExpression le) return new ProjectionExpression( WellKnownInterfaces.QueryableOfT.CachedMakeGenericType(le.Body.Type), itemProjector, - new Dictionary, Tuple>()); + TranslatedQuery.EmptyTupleParameterBindings); } } @@ -1529,11 +1501,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) { @@ -1710,11 +1678,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;