private object GetProjectionIndex(ProjectionBindingExpression projectionBindingExpression) => projectionBindingExpression.ProjectionMember != null ? ((ConstantExpression)_selectExpression.GetMappedProjection(projectionBindingExpression.ProjectionMember)).Value : (projectionBindingExpression.Index != null ? (object)projectionBindingExpression.Index : projectionBindingExpression.IndexMap);
private static EntityProjectionExpression GetMappedEntityProjectionExpression(SelectExpression selectExpression) => (EntityProjectionExpression)selectExpression.GetMappedProjection(new ProjectionMember());
private Expression TryExpand(Expression source, MemberIdentity member) { source = source.UnwrapTypeConversion(out var convertedType); if (!(source is EntityShaperExpression entityShaperExpression)) { return(null); } var entityType = entityShaperExpression.EntityType; if (convertedType != null) { entityType = entityType.GetRootType().GetDerivedTypesInclusive() .FirstOrDefault(et => et.ClrType == convertedType); if (entityType == null) { return(null); } } var navigation = member.MemberInfo != null ? entityType.FindNavigation(member.MemberInfo) : entityType.FindNavigation(member.Name); if (navigation == null) { return(null); } var targetEntityType = navigation.GetTargetType(); if (targetEntityType == null || (!targetEntityType.HasDefiningNavigation() && !targetEntityType.IsOwned())) { return(null); } var foreignKey = navigation.ForeignKey; if (navigation.IsCollection()) { var innerShapedQuery = CreateShapedQueryExpression( targetEntityType, _sqlExpressionFactory.SelectWithCrossDb(targetEntityType)); var makeNullable = foreignKey.PrincipalKey.Properties .Concat(foreignKey.Properties) .Select(p => p.ClrType) .Any(t => t.IsNullableType()); var innerSequenceType = innerShapedQuery.Type.TryGetSequenceType(); var correlationPredicateParameter = Expression.Parameter(innerSequenceType); var outerKey = entityShaperExpression.CreateKeyAccessExpression( navigation.IsDependentToPrincipal() ? foreignKey.Properties : foreignKey.PrincipalKey.Properties, makeNullable); var innerKey = correlationPredicateParameter.CreateKeyAccessExpression( navigation.IsDependentToPrincipal() ? foreignKey.PrincipalKey.Properties : foreignKey.Properties, makeNullable); var outerKeyFirstProperty = outerKey is NewExpression newExpression ? ((UnaryExpression)((NewArrayExpression)newExpression.Arguments[0]).Expressions[0]).Operand : outerKey; var predicate = outerKeyFirstProperty.Type.IsNullableType() ? Expression.AndAlso( Expression.NotEqual(outerKeyFirstProperty, Expression.Constant(null, outerKeyFirstProperty.Type)), Expression.Equal(outerKey, innerKey)) : Expression.Equal(outerKey, innerKey); var correlationPredicate = Expression.Lambda(predicate, correlationPredicateParameter); return(Expression.Call( QueryableMethods.Where.MakeGenericMethod(innerSequenceType), innerShapedQuery, Expression.Quote(correlationPredicate))); } var entityProjectionExpression = (EntityProjectionExpression) (entityShaperExpression.ValueBufferExpression is ProjectionBindingExpression projectionBindingExpression ? _selectExpression.GetMappedProjection(projectionBindingExpression.ProjectionMember) : entityShaperExpression.ValueBufferExpression); var innerShaper = entityProjectionExpression.BindNavigation(navigation); if (innerShaper == null) { var innerSelectExpression = _sqlExpressionFactory.SelectWithCrossDb(targetEntityType); var innerShapedQuery = CreateShapedQueryExpression(targetEntityType, innerSelectExpression); var makeNullable = foreignKey.PrincipalKey.Properties .Concat(foreignKey.Properties) .Select(p => p.ClrType) .Any(t => t.IsNullableType()); var outerKey = entityShaperExpression.CreateKeyAccessExpression( navigation.IsDependentToPrincipal() ? foreignKey.Properties : foreignKey.PrincipalKey.Properties, makeNullable); var innerKey = innerShapedQuery.ShaperExpression.CreateKeyAccessExpression( navigation.IsDependentToPrincipal() ? foreignKey.PrincipalKey.Properties : foreignKey.Properties, makeNullable); var joinPredicate = _sqlTranslator.Translate(Expression.Equal(outerKey, innerKey)); _selectExpression.AddLeftJoin(innerSelectExpression, joinPredicate, null); #pragma warning disable CA1826 // Do not use Enumerable methods on indexable collections. Instead use the collection directly var leftJoinTable = ((LeftJoinExpression)_selectExpression.Tables.Last()).Table; #pragma warning restore CA1826 // Do not use Enumerable methods on indexable collections. Instead use the collection directly innerShaper = new EntityShaperExpression( targetEntityType, new EntityProjectionExpression(targetEntityType, leftJoinTable, true), true); entityProjectionExpression.AddNavigationBinding(navigation, innerShaper); } return(innerShaper); }