Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ private Expression CreateEntity(IEntityExpression expression, Expression tupleEx
if (itemMaterializationContextParameter == null)
throw new InvalidOperationException(
string.Format(Strings.ExUnableToTranslateLambdaExpressionXBecauseItRequiresToMaterializeEntityOfTypeX,
context.Translator.state.CurrentLambda,
context.Translator.State.CurrentLambda,
expression.PersistentType.UnderlyingType.FullName));

var typeIdField = expression.Fields.SingleOrDefault(f => f.Name == WellKnown.TypeIdFieldName);
Expand Down
134 changes: 64 additions & 70 deletions Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.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: Alexis Kochetov
Expand Down Expand Up @@ -111,7 +111,7 @@ protected override Expression VisitUnary(UnaryExpression u)
return base.VisitUnary(u);
throw new InvalidOperationException(String.Format(Strings.ExDowncastFromXToXNotSupportedUseOfTypeOrAsOperatorInstead, u, u.Operand.Type, u.Type));
}
else if (u.Type==WellKnownTypes.Object && state.ShouldOmitConvertToObject) {
else if (u.Type==WellKnownTypes.Object && State.ShouldOmitConvertToObject) {
var expression = u.StripCasts();
return Visit(expression);
}
Expand All @@ -124,17 +124,16 @@ protected override Expression VisitUnary(UnaryExpression u)

protected override Expression VisitLambda(LambdaExpression le)
{
using (state.CreateLambdaScope(le)) {
state.AllowCalculableColumnCombine = false;
using (CreateLambdaScope(le, allowCalculableColumnCombine: false)) {
Expression body = le.Body;
if (!state.IsTailMethod)
if (!State.IsTailMethod)
body = NullComparsionRewriter.Rewrite(body);
body = Visit(body);
ParameterExpression parameter = le.Parameters[0];
var shouldTranslate =
(body.NodeType!=ExpressionType.New || body.IsNewExpressionSupportedByStorage())
&& body.NodeType!=ExpressionType.MemberInit
&& !(body.NodeType==ExpressionType.Constant && state.BuildingProjection);
&& !(body.NodeType==ExpressionType.Constant && State.BuildingProjection);
if (shouldTranslate)
body = body.IsProjection()
? BuildSubqueryResult((ProjectionExpression) body, le.Body.Type)
Expand All @@ -147,8 +146,7 @@ protected override Expression VisitLambda(LambdaExpression le)
protected override MemberAssignment VisitMemberAssignment(MemberAssignment ma)
{
Expression expression;
using (state.CreateScope()) {
state.CalculateExpressions = false;
using (CreateScope(new TranslatorState(State) { CalculateExpressions = false })) {
expression = Visit(ma.Expression);
}

Expand Down Expand Up @@ -230,8 +228,8 @@ private Expression ConvertEnum(Expression left)
/// <exception cref="InvalidOperationException"><c>InvalidOperationException</c>.</exception>
protected override Expression VisitParameter(ParameterExpression p)
{
bool isInnerParameter = state.Parameters.Contains(p);
bool isOuterParameter = state.OuterParameters.Contains(p);
bool isInnerParameter = State.Parameters.Contains(p);
bool isOuterParameter = State.OuterParameters.Contains(p);

if (!isInnerParameter && !isOuterParameter)
throw new InvalidOperationException(Strings.ExLambdaParameterIsOutOfScope);
Expand Down Expand Up @@ -314,8 +312,7 @@ protected override Expression VisitMemberAccess(MemberExpression ma)
throw new NotSupportedException(String.Format(Strings.ExFieldMustBePersistent, ma.ToString(true)));
}
Expression source;
using (state.CreateScope()) {
// state.BuildingProjection = false;
using (CreateScope(new TranslatorState(State) { /* BuildingProjection = false */ })) {
source = Visit(ma.Expression);
}

Expand All @@ -325,8 +322,7 @@ protected override Expression VisitMemberAccess(MemberExpression ma)

protected override Expression VisitMethodCall(MethodCallExpression mc)
{
using (state.CreateScope()) {
state.IsTailMethod = mc==context.Query && mc.IsQuery();
using (CreateScope(new TranslatorState(State) { IsTailMethod = mc == context.Query && mc.IsQuery() })) {
var method = mc.Method;
var customCompiler = context.CustomCompilerProvider.GetCompiler(method);
if (customCompiler != null) {
Expand Down Expand Up @@ -1076,7 +1072,7 @@ private Expression ProcessProjectionElement(Expression body)
var reduceCastBody = body.StripCasts();

var canCalculate =
state.CalculateExpressions
State.CalculateExpressions
&& reduceCastBody.GetMemberType()==MemberType.Unknown
&& (reduceCastBody.NodeType!=ExpressionType.New || reduceCastBody.IsNewExpressionSupportedByStorage())
&& reduceCastBody.NodeType!=ExpressionType.ArrayIndex
Expand All @@ -1086,7 +1082,7 @@ private Expression ProcessProjectionElement(Expression body)
if (!canCalculate)
return body;

var lambdaParameter = state.Parameters[0];
var lambdaParameter = State.Parameters[0];
var calculator = ExpressionMaterializer.MakeLambda(body, context);
var columnDescriptor = CreateCalculatedColumnDescriptor(calculator);
return AddCalculatedColumn(lambdaParameter, columnDescriptor, originalBodyType);
Expand All @@ -1105,7 +1101,7 @@ private CalculatedColumnDescriptor CreateCalculatedColumnDescriptor(LambdaExpres
private ColumnExpression AddCalculatedColumn(ParameterExpression sourceParameter, CalculatedColumnDescriptor descriptor, Type originalColumnType)
{
var oldResult = context.Bindings[sourceParameter];
var isInlined = !state.BuildingProjection && !state.GroupingKey;
var isInlined = !State.BuildingProjection && !State.GroupingKey;
var dataSource = oldResult.ItemProjector.DataSource;

SortProvider sortProvider = null;
Expand All @@ -1115,7 +1111,7 @@ private ColumnExpression AddCalculatedColumn(ParameterExpression sourceParameter
}

var columns = new List<CalculatedColumnDescriptor>();
if (state.AllowCalculableColumnCombine && dataSource is CalculateProvider && isInlined==((CalculateProvider) dataSource).IsInlined) {
if (State.AllowCalculableColumnCombine && dataSource is CalculateProvider && isInlined==((CalculateProvider) dataSource).IsInlined) {
var calculateProvider = ((CalculateProvider) dataSource);
var presentColumns = calculateProvider
.CalculatedColumns
Expand All @@ -1134,7 +1130,7 @@ private ColumnExpression AddCalculatedColumn(ParameterExpression sourceParameter
context.Bindings.ReplaceBound(sourceParameter, newResult);

var result = ColumnExpression.Create(originalColumnType, dataSource.Header.Length - 1);
state.AllowCalculableColumnCombine = true;
ModifyStateAllowCalculableColumnCombine(true);

return result;
}
Expand Down Expand Up @@ -1167,20 +1163,20 @@ private Expression ConstructQueryable(MethodCallExpression mc)

private Expression BuildSubqueryResult(ProjectionExpression subQuery, Type resultType)
{
if (state.Parameters.Length==0)
if (State.Parameters.Length==0)
throw Exceptions.InternalError(String.Format(Strings.ExUnableToBuildSubqueryResultForExpressionXStateContainsNoParameters, subQuery), OrmLog.Instance);

if (!resultType.IsOfGenericInterface(WellKnownInterfaces.EnumerableOfT))
throw Exceptions.InternalError(String.Format(Strings.ExUnableToBuildSubqueryResultForExpressionXResultTypeIsNotIEnumerable, subQuery), OrmLog.Instance);

ApplyParameter applyParameter = context.GetApplyParameter(context.Bindings[state.Parameters[0]]);
ApplyParameter applyParameter = context.GetApplyParameter(context.Bindings[State.Parameters[0]]);
if (subQuery.Type!=resultType)
subQuery = new ProjectionExpression(
resultType,
subQuery.ItemProjector,
subQuery.TupleParameterBindings,
subQuery.ResultAccessMethod);
return new SubQueryExpression(resultType, state.Parameters[0], false, subQuery, applyParameter);
return new SubQueryExpression(resultType, State.Parameters[0], false, subQuery, applyParameter);
}

private static IList<Expression> GetAnonymousArguments(Expression expression, Type anonymousTypeForNullValues = null)
Expand Down Expand Up @@ -1398,55 +1394,53 @@ private Expression VisitTypeAs(Expression source, Type targetType)
return Visit(Expression.Convert(source, targetType));

// Cast to subclass or interface.
using (state.CreateScope()) {
var targetTypeInfo = context.Model.Types[targetType];
// Using of state.Parameter[0] is a very weak approach.
// `as` operator could be applied on expression that has no relation with current parameter
// thus the later code will fail.
// We can't easily find real parameter that need replacement.
// We work around this situation by supporting some known cases.
// The simplest (and the only at moment) case is a source being chain of MemberExpressions.
var currentParameter = state.Parameters[0];
var parameter = (source.StripMemberAccessChain() as ParameterExpression) ?? currentParameter;
var entityExpression = visitedSource.StripCasts().StripMarkers() as IEntityExpression;

if (entityExpression==null)
throw new InvalidOperationException(Strings.ExAsOperatorSupportsEntityOnly);

// Replace original recordset. New recordset is left join with old recordset
ProjectionExpression originalResultExpression = context.Bindings[parameter];
var originalQuery = originalResultExpression.ItemProjector.DataSource;
int offset = originalQuery.Header.Columns.Count;

// Join primary index of target type
IndexInfo indexToJoin = targetTypeInfo.Indexes.PrimaryIndex;
var queryToJoin = indexToJoin.GetQuery().Alias(context.GetNextAlias());
var keySegment = entityExpression.Key.Mapping.GetItems();
var keyPairs = keySegment
.Select((leftIndex, rightIndex) => new Pair<int>(leftIndex, rightIndex))
.ToArray();

// Replace recordset.
var joinedRecordQuery = originalQuery.LeftJoin(queryToJoin, keyPairs);
var itemProjectorExpression = new ItemProjectorExpression(
originalResultExpression.ItemProjector.Item, joinedRecordQuery, context);
var projectionExpression = new ProjectionExpression(
originalResultExpression.Type, itemProjectorExpression, originalResultExpression.TupleParameterBindings);
context.Bindings.ReplaceBound(parameter, projectionExpression);

// return new EntityExpression
var result = EntityExpression.Create(context.Model.Types[targetType], offset, false);
result.IsNullable = true;
if (parameter!=currentParameter)
result = (EntityExpression) result.BindParameter(parameter, new Dictionary<Expression, Expression>());
return result;
}
var targetTypeInfo = context.Model.Types[targetType];
// Using of state.Parameter[0] is a very weak approach.
// `as` operator could be applied on expression that has no relation with current parameter
// thus the later code will fail.
// We can't easily find real parameter that need replacement.
// We work around this situation by supporting some known cases.
// The simplest (and the only at moment) case is a source being chain of MemberExpressions.
var currentParameter = State.Parameters[0];
var parameter = (source.StripMemberAccessChain() as ParameterExpression) ?? currentParameter;
var entityExpression = visitedSource.StripCasts().StripMarkers() as IEntityExpression;

if (entityExpression==null)
throw new InvalidOperationException(Strings.ExAsOperatorSupportsEntityOnly);

// Replace original recordset. New recordset is left join with old recordset
ProjectionExpression originalResultExpression = context.Bindings[parameter];
var originalQuery = originalResultExpression.ItemProjector.DataSource;
int offset = originalQuery.Header.Columns.Count;

// Join primary index of target type
IndexInfo indexToJoin = targetTypeInfo.Indexes.PrimaryIndex;
var queryToJoin = indexToJoin.GetQuery().Alias(context.GetNextAlias());
var keySegment = entityExpression.Key.Mapping.GetItems();
var keyPairs = keySegment
.Select((leftIndex, rightIndex) => new Pair<int>(leftIndex, rightIndex))
.ToArray();

// Replace recordset.
var joinedRecordQuery = originalQuery.LeftJoin(queryToJoin, keyPairs);
var itemProjectorExpression = new ItemProjectorExpression(
originalResultExpression.ItemProjector.Item, joinedRecordQuery, context);
var projectionExpression = new ProjectionExpression(
originalResultExpression.Type, itemProjectorExpression, originalResultExpression.TupleParameterBindings);
context.Bindings.ReplaceBound(parameter, projectionExpression);

// return new EntityExpression
var result = EntityExpression.Create(context.Model.Types[targetType], offset, false);
result.IsNullable = true;
if (parameter!=currentParameter)
result = (EntityExpression) result.BindParameter(parameter, new Dictionary<Expression, Expression>());
return result;
}

private void EnsureEntityFieldsAreJoined(EntityExpression entityExpression)
{
ItemProjectorExpression itemProjector = entityExpression.OuterParameter==null
? context.Bindings[state.Parameters[0]].ItemProjector
? context.Bindings[State.Parameters[0]].ItemProjector
: context.Bindings[entityExpression.OuterParameter].ItemProjector;
EnsureEntityFieldsAreJoined(entityExpression, itemProjector);
}
Expand Down Expand Up @@ -1485,7 +1479,7 @@ private void EnsureEntityReferenceIsJoined(EntityFieldExpression entityFieldExpr
.Select((leftIndex, rightIndex) => new Pair<int>(leftIndex, rightIndex))
.ToArray();
ItemProjectorExpression originalItemProjector = entityFieldExpression.OuterParameter==null
? context.Bindings[state.Parameters[0]].ItemProjector
? context.Bindings[State.Parameters[0]].ItemProjector
: context.Bindings[entityFieldExpression.OuterParameter].ItemProjector;
int offset = originalItemProjector.DataSource.Header.Length;
var oldDataSource = originalItemProjector.DataSource;
Expand Down Expand Up @@ -1551,13 +1545,13 @@ private static Expression MakeBooleanExpression(Expression previous, Expression

private static ProjectionExpression CreateLocalCollectionProjectionExpression(Type itemType, object value, Translator translator, Expression sourceExpression)
{
var storedEntityType = translator.state.TypeOfEntityStoredInKey;
var storedEntityType = translator.State.TypeOfEntityStoredInKey;
var itemToTupleConverter = ItemToTupleConverter.BuildConverter(itemType, storedEntityType, value, translator.context.Model, sourceExpression);
var rsHeader = new RecordSetHeader(itemToTupleConverter.TupleDescriptor, itemToTupleConverter.TupleDescriptor.Select(x => new SystemColumn(translator.context.GetNextColumnAlias(), 0, x)).Cast<Column>());
var rawProvider = new RawProvider(rsHeader, itemToTupleConverter.GetEnumerable());
var recordset = new StoreProvider(rawProvider);
var itemProjector = new ItemProjectorExpression(itemToTupleConverter.Expression, recordset, translator.context);
if (translator.state.JoinLocalCollectionEntity)
if (translator.State.JoinLocalCollectionEntity)
itemProjector = EntityExpressionJoiner.JoinEntities(translator, itemProjector);
return new ProjectionExpression(itemType, itemProjector, new Dictionary<Parameter<Tuple>, Tuple>());
}
Expand Down Expand Up @@ -1650,4 +1644,4 @@ private void ArrangeContainsTableParameters(System.Collections.ObjectModel.ReadO

#endregion
}
}
}
4 changes: 1 addition & 3 deletions Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ private List<Expression> VisitNewExpressionArguments(NewExpression n)
var arguments = new List<Expression>();
foreach (var argument in n.Arguments) {
Expression body;
using (state.CreateScope()) {
state.CalculateExpressions = false;
using (CreateScope(new TranslatorState(State) { CalculateExpressions = false })) {
body = Visit(argument);
}
body = body.IsProjection()
Expand Down Expand Up @@ -203,7 +202,6 @@ internal Translator(TranslatorContext context, CompiledQueryProcessingScope comp
{
this.compiledQueryScope = compiledQueryScope;
this.context = context;
state = new TranslatorState(this);
}

static Translator()
Expand Down
Loading