protected override ShapedQueryExpression TranslateJoin( ShapedQueryExpression outer, ShapedQueryExpression inner, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, LambdaExpression resultSelector) { outerKeySelector = TranslateLambdaExpression(outer, outerKeySelector); innerKeySelector = TranslateLambdaExpression(inner, innerKeySelector); if (outerKeySelector == null || innerKeySelector == null) { return(null); } (outerKeySelector, innerKeySelector) = AlignKeySelectorTypes(outerKeySelector, innerKeySelector); var transparentIdentifierType = TransparentIdentifierFactory.Create( resultSelector.Parameters[0].Type, resultSelector.Parameters[1].Type); ((InMemoryQueryExpression)outer.QueryExpression).AddInnerJoin( (InMemoryQueryExpression)inner.QueryExpression, outerKeySelector, innerKeySelector, transparentIdentifierType); return(TranslateResultSelectorForJoin( outer, resultSelector, inner.ShaperExpression, transparentIdentifierType)); }
protected override ShapedQueryExpression TranslateLeftJoin( ShapedQueryExpression outer, ShapedQueryExpression inner, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, LambdaExpression resultSelector) { var joinPredicate = CreateJoinPredicate(outer, outerKeySelector, inner, innerKeySelector); if (joinPredicate != null) { var transparentIdentifierType = TransparentIdentifierFactory.Create( resultSelector.Parameters[0].Type, resultSelector.Parameters[1].Type); ((SelectExpression)outer.QueryExpression).AddLeftJoin( (SelectExpression)inner.QueryExpression, joinPredicate, transparentIdentifierType); return(TranslateResultSelectorForJoin( outer, resultSelector, MarkShaperNullable(inner.ShaperExpression), transparentIdentifierType)); } return(null); }
protected override ShapedQueryExpression TranslateSelectMany( ShapedQueryExpression source, LambdaExpression collectionSelector, LambdaExpression resultSelector) { var collectionSelectorBody = collectionSelector.Body; //var defaultIfEmpty = false; if (collectionSelectorBody is MethodCallExpression collectionEndingMethod && collectionEndingMethod.Method.IsGenericMethod && collectionEndingMethod.Method.GetGenericMethodDefinition() == _defaultIfEmptyWithoutArgMethodInfo) { //defaultIfEmpty = true; collectionSelectorBody = collectionEndingMethod.Arguments[0]; } var correlated = new CorrelationFindingExpressionVisitor().IsCorrelated(collectionSelectorBody, collectionSelector.Parameters[0]); if (correlated) { // TODO visit inner with outer parameter; // See #17236 throw new InvalidOperationException(CoreStrings.TranslationFailed( collectionSelector.Print() + "; " + resultSelector.Print())); } else { if (Visit(collectionSelectorBody) is ShapedQueryExpression inner) { var transparentIdentifierType = TransparentIdentifierFactory.Create( resultSelector.Parameters[0].Type, resultSelector.Parameters[1].Type); ((InMemoryQueryExpression)source.QueryExpression).AddCrossJoin( (InMemoryQueryExpression)inner.QueryExpression, transparentIdentifierType); return(TranslateResultSelectorForJoin( source, resultSelector, inner.ShaperExpression, transparentIdentifierType)); } } throw new NotImplementedException(); }
protected override ShapedQueryExpression TranslateLeftJoin(ShapedQueryExpression outer, ShapedQueryExpression inner, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, LambdaExpression resultSelector) { outerKeySelector = TranslateLambdaExpression(outer, outerKeySelector); innerKeySelector = TranslateLambdaExpression(inner, innerKeySelector); var transparentIdentifierType = TransparentIdentifierFactory.Create( resultSelector.Parameters[0].Type, resultSelector.Parameters[1].Type); ((InMemoryQueryExpression)outer.QueryExpression).AddLeftJoin( (InMemoryQueryExpression)inner.QueryExpression, outerKeySelector, innerKeySelector, transparentIdentifierType); return(TranslateResultSelectorForJoin( outer, resultSelector, MarkShaperNullable(inner.ShaperExpression), transparentIdentifierType)); }
public virtual void AddLeftJoin( InMemoryQueryExpression innerQueryExpression, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, Type transparentIdentifierType) { // GroupJoin phase var groupTransparentIdentifierType = TransparentIdentifierFactory.Create( typeof(ValueBuffer), typeof(IEnumerable <ValueBuffer>)); var outerParameter = Parameter(typeof(ValueBuffer), "outer"); var innerParameter = Parameter(typeof(IEnumerable <ValueBuffer>), "inner"); var outerMemberInfo = groupTransparentIdentifierType.GetTypeInfo().GetDeclaredField("Outer"); var innerMemberInfo = groupTransparentIdentifierType.GetTypeInfo().GetDeclaredField("Inner"); var resultSelector = Lambda( New( groupTransparentIdentifierType.GetTypeInfo().DeclaredConstructors.Single(), new[] { outerParameter, innerParameter }, new[] { outerMemberInfo, innerMemberInfo }), outerParameter, innerParameter); var groupJoinExpression = Call( InMemoryLinqOperatorProvider.GroupJoin.MakeGenericMethod( typeof(ValueBuffer), typeof(ValueBuffer), outerKeySelector.ReturnType, groupTransparentIdentifierType), ServerQueryExpression, innerQueryExpression.ServerQueryExpression, outerKeySelector, innerKeySelector, resultSelector); // SelectMany phase var collectionParameter = Parameter(groupTransparentIdentifierType, "collection"); var collection = MakeMemberAccess(collectionParameter, innerMemberInfo); outerParameter = Parameter(groupTransparentIdentifierType, "outer"); innerParameter = Parameter(typeof(ValueBuffer), "inner"); var resultValueBufferExpressions = new List <Expression>(); var projectionMapping = new Dictionary <ProjectionMember, Expression>(); var replacingVisitor = new ReplacingExpressionVisitor( new Dictionary <Expression, Expression> { { ValueBufferParameter, MakeMemberAccess(outerParameter, outerMemberInfo) }, { innerQueryExpression.ValueBufferParameter, innerParameter } }); var index = 0; outerMemberInfo = transparentIdentifierType.GetTypeInfo().GetDeclaredField("Outer"); foreach (var projection in _projectionMapping) { if (projection.Value is EntityProjectionExpression entityProjection) { var readExpressionMap = new Dictionary <IProperty, Expression>(); foreach (var property in GetAllPropertiesInHierarchy(entityProjection.EntityType)) { var replacedExpression = replacingVisitor.Visit(entityProjection.BindProperty(property)); resultValueBufferExpressions.Add(replacedExpression); readExpressionMap[property] = CreateReadValueExpression(replacedExpression.Type, index++, property); } projectionMapping[projection.Key.Prepend(outerMemberInfo)] = new EntityProjectionExpression(entityProjection.EntityType, readExpressionMap); } else { var replacedExpression = replacingVisitor.Visit(projection.Value); resultValueBufferExpressions.Add(replacedExpression); projectionMapping[projection.Key.Prepend(outerMemberInfo)] = CreateReadValueExpression(replacedExpression.Type, index++, InferPropertyFromInner(projection.Value)); } } var outerIndex = index; innerMemberInfo = transparentIdentifierType.GetTypeInfo().GetDeclaredField("Inner"); var nullableReadValueExpressionVisitor = new NullableReadValueExpressionVisitor(); foreach (var projection in innerQueryExpression._projectionMapping) { if (projection.Value is EntityProjectionExpression entityProjection) { var readExpressionMap = new Dictionary <IProperty, Expression>(); foreach (var property in GetAllPropertiesInHierarchy(entityProjection.EntityType)) { var replacedExpression = replacingVisitor.Visit(entityProjection.BindProperty(property)); replacedExpression = nullableReadValueExpressionVisitor.Visit(replacedExpression); resultValueBufferExpressions.Add(replacedExpression); readExpressionMap[property] = CreateReadValueExpression(replacedExpression.Type, index++, property); } projectionMapping[projection.Key.Prepend(innerMemberInfo)] = new EntityProjectionExpression(entityProjection.EntityType, readExpressionMap); } else { var replacedExpression = replacingVisitor.Visit(projection.Value); replacedExpression = nullableReadValueExpressionVisitor.Visit(replacedExpression); resultValueBufferExpressions.Add(replacedExpression); projectionMapping[projection.Key.Prepend(innerMemberInfo)] = CreateReadValueExpression(replacedExpression.Type, index++, InferPropertyFromInner(projection.Value)); } } var collectionSelector = Lambda( Call( InMemoryLinqOperatorProvider.DefaultIfEmptyWithArg.MakeGenericMethod(typeof(ValueBuffer)), collection, New( _valueBufferConstructor, NewArrayInit( typeof(object), Enumerable.Range(0, index - outerIndex).Select(i => Constant(null))))), collectionParameter); resultSelector = Lambda( New( _valueBufferConstructor, NewArrayInit( typeof(object), resultValueBufferExpressions .Select(e => e.Type.IsValueType ? Convert(e, typeof(object)) : e) .ToArray())), outerParameter, innerParameter); ServerQueryExpression = Call( InMemoryLinqOperatorProvider.SelectMany.MakeGenericMethod( groupTransparentIdentifierType, typeof(ValueBuffer), typeof(ValueBuffer)), groupJoinExpression, collectionSelector, resultSelector); _projectionMapping = projectionMapping; }
public virtual EntityShaperExpression AddNavigationToWeakEntityType( EntityProjectionExpression entityProjectionExpression, INavigation navigation, InMemoryQueryExpression innerQueryExpression, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector) { // GroupJoin phase var groupTransparentIdentifierType = TransparentIdentifierFactory.Create( typeof(ValueBuffer), typeof(IEnumerable <ValueBuffer>)); var outerParameter = Parameter(typeof(ValueBuffer), "outer"); var innerParameter = Parameter(typeof(IEnumerable <ValueBuffer>), "inner"); var outerMemberInfo = groupTransparentIdentifierType.GetTypeInfo().GetDeclaredField("Outer"); var innerMemberInfo = groupTransparentIdentifierType.GetTypeInfo().GetDeclaredField("Inner"); var resultSelector = Lambda( New( groupTransparentIdentifierType.GetTypeInfo().DeclaredConstructors.Single(), new[] { outerParameter, innerParameter }, new[] { outerMemberInfo, innerMemberInfo }), outerParameter, innerParameter); var groupJoinExpression = Call( InMemoryLinqOperatorProvider.GroupJoin.MakeGenericMethod( typeof(ValueBuffer), typeof(ValueBuffer), outerKeySelector.ReturnType, groupTransparentIdentifierType), ServerQueryExpression, innerQueryExpression.ServerQueryExpression, outerKeySelector, innerKeySelector, resultSelector); // SelectMany phase var collectionParameter = Parameter(groupTransparentIdentifierType, "collection"); var collection = MakeMemberAccess(collectionParameter, innerMemberInfo); outerParameter = Parameter(groupTransparentIdentifierType, "outer"); innerParameter = Parameter(typeof(ValueBuffer), "inner"); var resultValueBufferExpressions = new List <Expression>(); var projectionMapping = new Dictionary <ProjectionMember, Expression>(); var replacingVisitor = new ReplacingExpressionVisitor( new Dictionary <Expression, Expression> { { CurrentParameter, MakeMemberAccess(outerParameter, outerMemberInfo) }, { innerQueryExpression.CurrentParameter, innerParameter } }); var index = 0; EntityProjectionExpression copyEntityProjectionToOuter(EntityProjectionExpression entityProjection) { var readExpressionMap = new Dictionary <IProperty, Expression>(); foreach (var property in GetAllPropertiesInHierarchy(entityProjection.EntityType)) { var replacedExpression = replacingVisitor.Visit(entityProjection.BindProperty(property)); resultValueBufferExpressions.Add(replacedExpression); readExpressionMap[property] = CreateReadValueExpression(replacedExpression.Type, index++, property); } var newEntityProjection = new EntityProjectionExpression(entityProjection.EntityType, readExpressionMap); if (ReferenceEquals(entityProjectionExpression, entityProjection)) { entityProjectionExpression = newEntityProjection; } // Also lift nested entity projections foreach (var navigation in entityProjection.EntityType.GetTypesInHierarchy() .SelectMany(EntityTypeExtensions.GetDeclaredNavigations)) { var boundEntityShaperExpression = entityProjection.BindNavigation(navigation); if (boundEntityShaperExpression != null) { var innerEntityProjection = (EntityProjectionExpression)boundEntityShaperExpression.ValueBufferExpression; var newInnerEntityProjection = copyEntityProjectionToOuter(innerEntityProjection); boundEntityShaperExpression = boundEntityShaperExpression.Update(newInnerEntityProjection); newEntityProjection.AddNavigationBinding(navigation, boundEntityShaperExpression); } } return(newEntityProjection); } foreach (var projection in _projectionMapping) { if (projection.Value is EntityProjectionExpression entityProjection) { projectionMapping[projection.Key] = copyEntityProjectionToOuter(entityProjection); } else { var replacedExpression = replacingVisitor.Visit(projection.Value); resultValueBufferExpressions.Add(replacedExpression); projectionMapping[projection.Key] = CreateReadValueExpression(replacedExpression.Type, index++, InferPropertyFromInner(projection.Value)); } } _projectionMapping = projectionMapping; var outerIndex = index; var nullableReadValueExpressionVisitor = new NullableReadValueExpressionVisitor(); var innerEntityProjection = (EntityProjectionExpression)innerQueryExpression.GetMappedProjection(new ProjectionMember()); var innerReadExpressionMap = new Dictionary <IProperty, Expression>(); foreach (var property in GetAllPropertiesInHierarchy(innerEntityProjection.EntityType)) { var replacedExpression = replacingVisitor.Visit(innerEntityProjection.BindProperty(property)); replacedExpression = nullableReadValueExpressionVisitor.Visit(replacedExpression); resultValueBufferExpressions.Add(replacedExpression); innerReadExpressionMap[property] = CreateReadValueExpression(replacedExpression.Type, index++, property); } innerEntityProjection = new EntityProjectionExpression(innerEntityProjection.EntityType, innerReadExpressionMap); var collectionSelector = Lambda( Call( InMemoryLinqOperatorProvider.DefaultIfEmptyWithArgument.MakeGenericMethod(typeof(ValueBuffer)), collection, New( _valueBufferConstructor, NewArrayInit( typeof(object), Enumerable.Range(0, index - outerIndex).Select(i => Constant(null))))), collectionParameter); resultSelector = Lambda( New( _valueBufferConstructor, NewArrayInit( typeof(object), resultValueBufferExpressions .Select(e => e.Type.IsValueType ? Convert(e, typeof(object)) : e) .ToArray())), outerParameter, innerParameter); ServerQueryExpression = Call( InMemoryLinqOperatorProvider.SelectManyWithCollectionSelector.MakeGenericMethod( groupTransparentIdentifierType, typeof(ValueBuffer), typeof(ValueBuffer)), groupJoinExpression, collectionSelector, resultSelector); var entityShaper = new EntityShaperExpression(innerEntityProjection.EntityType, innerEntityProjection, nullable: true); entityProjectionExpression.AddNavigationBinding(navigation, entityShaper); return(entityShaper); }
protected override ShapedQueryExpression TranslateSelectMany( ShapedQueryExpression source, LambdaExpression collectionSelector, LambdaExpression resultSelector) { var(newCollectionSelector, correlated, defaultIfEmpty) = new CorrelationFindingExpressionVisitor().IsCorrelated(collectionSelector); if (correlated) { var collectionSelectorBody = RemapLambdaBody(source, newCollectionSelector); if (Visit(collectionSelectorBody) is ShapedQueryExpression inner) { var transparentIdentifierType = TransparentIdentifierFactory.Create( resultSelector.Parameters[0].Type, resultSelector.Parameters[1].Type); var innerShaperExpression = inner.ShaperExpression; if (defaultIfEmpty) { ((SelectExpression)source.QueryExpression).AddOuterApply( (SelectExpression)inner.QueryExpression, transparentIdentifierType); innerShaperExpression = MarkShaperNullable(innerShaperExpression); } else { ((SelectExpression)source.QueryExpression).AddCrossApply( (SelectExpression)inner.QueryExpression, transparentIdentifierType); } return(TranslateResultSelectorForJoin( source, resultSelector, innerShaperExpression, transparentIdentifierType)); } } else { if (Visit(newCollectionSelector.Body) is ShapedQueryExpression inner) { if (defaultIfEmpty) { inner = TranslateDefaultIfEmpty(inner, null); if (inner == null) { return(null); } } var transparentIdentifierType = TransparentIdentifierFactory.Create( resultSelector.Parameters[0].Type, resultSelector.Parameters[1].Type); ((SelectExpression)source.QueryExpression).AddCrossJoin( (SelectExpression)inner.QueryExpression, transparentIdentifierType); return(TranslateResultSelectorForJoin( source, resultSelector, inner.ShaperExpression, transparentIdentifierType)); } } return(null); }