public override Expression Visit(Expression node) { switch (node) { case DefaultIfEmptyExpression defaultIfEmptyExpression: { return(Expression.Condition( test: Expression.Call( readerParameter, isDBNullMethodInfo, Expression.Constant(readerIndex++)), ifTrue: Expression.Default(defaultIfEmptyExpression.Type), ifFalse: Visit(defaultIfEmptyExpression.Expression))); } case PolymorphicExpression polymorphicExpression: { var variables = new List <ParameterExpression>(); var expressions = new List <Expression>(); var rowValue = polymorphicExpression.Row; var rowVariable = Expression.Variable(rowValue.Type, "row"); var rowParameterExpansion = (Expression)rowVariable; if (rowValue is ExtraPropertiesExpression extraPropertiesExpression) { extraPropertiesExpression = VisitAndConvert(extraPropertiesExpression, nameof(Visit)); var properties = new List <Expression>(); for (var i = 0; i < extraPropertiesExpression.Names.Count; i++) { var propertyName = extraPropertiesExpression.Names[i]; var propertyValue = extraPropertiesExpression.Properties[i]; var propertyVariable = Expression.Variable(propertyValue.Type, propertyName); variables.Add(propertyVariable); properties.Add(propertyVariable); expressions.Add(Expression.Assign(propertyVariable, propertyValue)); } rowValue = Visit(extraPropertiesExpression.Expression); rowVariable = Expression.Variable(rowValue.Type, "row"); rowParameterExpansion = extraPropertiesExpression.Update(rowVariable, properties); } else { rowValue = Visit(rowValue); } variables.Add(rowVariable); expressions.Add(Expression.Assign(rowVariable, rowValue)); var useSwitchBlock = polymorphicExpression.Descriptors .All(d => d.Test.Body.NodeType == ExpressionType.Equal && ((BinaryExpression)d.Test.Body).Right is ConstantExpression constant && constant.Type.IsConstantLiteralType()); if (useSwitchBlock) { var result = Expression.Parameter(polymorphicExpression.Type); var cases = new SwitchCase[polymorphicExpression.Descriptors.Count()]; //var breakTarget = Expression.Label(); var i = 0; foreach (var descriptor in polymorphicExpression.Descriptors) { var materializer = descriptor.Materializer.ExpandParameters(rowParameterExpansion); var expansion = Expression.Convert(materializer, polymorphicExpression.Type); var assignment = Expression.Assign(result, expansion); var testValue = ((BinaryExpression)descriptor.Test.Body).Right; var body = assignment; //Expression.Block(assignment, Expression.Break(breakTarget)); cases[i] = Expression.SwitchCase(body, testValue); i++; } variables.Add(result); expressions.Add( Expression.Switch( ((BinaryExpression)polymorphicExpression.Descriptors.First().Test.ExpandParameters(rowParameterExpansion)).Left, Expression.Assign(result, Expression.Default(polymorphicExpression.Type)), cases)); //expressions.Add(Expression.Label(breakTarget)); expressions.Add(result); } else { var result = Expression.Default(polymorphicExpression.Type) as Expression; foreach (var descriptor in polymorphicExpression.Descriptors) { var test = descriptor.Test.ExpandParameters(rowParameterExpansion); var materializer = descriptor.Materializer.ExpandParameters(rowParameterExpansion); var expansion = Expression.Convert(materializer, polymorphicExpression.Type); result = Expression.Condition(test, expansion, result, polymorphicExpression.Type); } expressions.Add(result); } return(Expression.Block(variables, expressions)); } default: { var visited = base.Visit(node); if (visited is ExtraPropertiesExpression || visited is NewExpression) { return(visited); } var parts = GetNameParts().ToArray(); var identifier = $"Materialize_"; if (parts.Length == 0) { identifier += "$root"; } else if (parts.Length == 1) { identifier += parts[0]; } else { identifier += $"{parts.First()}_{{{parts.Length - 2}}}_{parts.Last()}"; } if (identifierCounts.TryGetValue(identifier, out var count)) { identifierCounts[identifier] = count + 1; identifier += $"_{count}"; } else { identifierCounts[identifier] = 1; identifier += "_0"; } return(MaterializationUtilities.Invoke(visited, identifier)); } } }
public override Expression Visit(Expression node) { switch (node) { case EntityMaterializationExpression entityMaterializationExpression: { var entityVariable = Expression.Variable(node.Type, "entity"); var shadowPropertiesVariable = Expression.Variable(typeof(object[]), "shadow"); var entityType = entityMaterializationExpression.EntityType; var materializer = Visit(entityMaterializationExpression.Expression); var getEntityMethodInfo = default(MethodInfo); switch (entityMaterializationExpression.IdentityMapMode) { case IdentityMapMode.StateManager: { getEntityMethodInfo = EntityTrackingHelper.GetEntityUsingStateManagerMethodInfo; break; } case IdentityMapMode.IdentityMap: default: { getEntityMethodInfo = EntityTrackingHelper.GetEntityUsingIdentityMapMethodInfo; break; } } var shadowPropertiesExpression = (Expression)Expression.Constant(new object[0]); var shadowProperties = entityMaterializationExpression.ShadowProperties; if (!shadowProperties.IsDefaultOrEmpty) { var values = Enumerable .Repeat(Expression.Constant(null), entityType.PropertyCount()) .Cast <Expression>() .ToArray(); for (var i = 0; i < shadowProperties.Length; i++) { values[shadowProperties[i].GetIndex()] = Expression.Convert( entityMaterializationExpression.Properties[i], typeof(object)); } shadowPropertiesExpression = Expression.NewArrayInit(typeof(object), values); } var result = Expression.Block( variables: new ParameterExpression[] { entityVariable, shadowPropertiesVariable, }, expressions: new Expression[] { Expression.Assign( shadowPropertiesVariable, shadowPropertiesExpression), Expression.Assign( entityVariable, new CollectionNavigationFixupExpressionVisitor(model) .Visit(materializer)), Expression.Convert( Expression.Call( getEntityMethodInfo, Expression.Convert(executionContextParameter, typeof(EFCoreDbCommandExecutor)), Expression.Constant(entityType), entityMaterializationExpression.KeyExpression .UnwrapLambda() .ExpandParameters(entityVariable, shadowPropertiesVariable), entityVariable, shadowPropertiesVariable, Expression.Constant(entityMaterializationExpression.IncludedNavigations.ToList())), node.Type) }); var identifier = $"MaterializeEntity_{entityType.DisplayName()}"; if (identifierCounts.TryGetValue(identifier, out var count)) { identifierCounts[identifier] = count + 1; identifier += $"_{count}"; } else { identifierCounts[identifier] = 1; identifier += "_0"; } return(MaterializationUtilities.Invoke(result, identifier)); } default: { return(base.Visit(node)); } } }