public static Expression <Func <Tuple, bool> > BuildFilterLambda(int startIndex, IReadOnlyList <Type> keyColumnTypes, Parameter <Tuple> keyParameter) { Expression filterExpression = null; var tupleParameter = Expression.Parameter(WellKnownOrmTypes.Tuple, "tuple"); var valueProperty = WellKnownOrmTypes.ParameterOfTuple .GetProperty(nameof(Parameter <Tuple> .Value), WellKnownOrmTypes.Tuple); var keyValue = Expression.Property(Expression.Constant(keyParameter), valueProperty); for (var i = 0; i < keyColumnTypes.Count; i++) { var getValueMethod = WellKnownMembers.Tuple.GenericAccessor.MakeGenericMethod(keyColumnTypes[i]); var tupleParameterFieldAccess = Expression.Call( tupleParameter, getValueMethod, Expression.Constant(startIndex + i)); var keyParameterFieldAccess = Expression.Call( keyValue, getValueMethod, Expression.Constant(i)); if (filterExpression == null) { filterExpression = Expression.Equal(tupleParameterFieldAccess, keyParameterFieldAccess); } else { filterExpression = Expression.And(filterExpression, Expression.Equal(tupleParameterFieldAccess, keyParameterFieldAccess)); } } return(FastExpression.Lambda <Func <Tuple, bool> >(filterExpression, tupleParameter)); }
private static MethodCallExpression AddProjectionPrefetch(Expression source, LambdaExpression projection) { var itemType = QueryHelper.GetSequenceElementType(source.Type); var projectionType = projection.Body.Type; var wrapperType = typeof(ProjectionWrapper <,>).MakeGenericType(itemType, projectionType); var wrapperItemProperty = wrapperType.GetProperty("Item"); var wrapperProjectedProperty = wrapperType.GetProperty("Projected"); var wrapperProjectionParameter = projection.Parameters[0]; var wrapperProjectionLambda = FastExpression.Lambda( Expression.MemberInit( Expression.New(wrapperType), Expression.Bind(wrapperItemProperty, wrapperProjectionParameter), Expression.Bind(wrapperProjectedProperty, projection.Body) ), wrapperProjectionParameter); var wrapperProjection = QueryFactory.Select(source, wrapperProjectionLambda); var resultProjectionParameter = Expression.Parameter(wrapperType, "wrapper"); var resultProjectionLambda = FastExpression.Lambda( Expression.MakeMemberAccess(resultProjectionParameter, wrapperItemProperty), resultProjectionParameter); var resultProjection = QueryFactory.Select(wrapperProjection, resultProjectionLambda); return(resultProjection); }
BuildMaterializer(ProjectionExpression projection, IEnumerable <Parameter <Tuple> > tupleParameters) { var tupleReader = Expression.Parameter(typeof(RecordSetReader), "tupleReader"); var session = Expression.Parameter(typeof(Session), "session"); var parameterContext = Expression.Parameter(WellKnownOrmTypes.ParameterContext, "parameterContext"); var itemProjector = projection.ItemProjector; var materializationInfo = itemProjector.Materialize(context, tupleParameters); var elementType = itemProjector.Item.Type; var materializeMethod = MaterializationHelper.MaterializeMethodInfo.MakeGenericMethod(elementType); var itemMaterializerFactoryMethod = elementType.IsNullable() ? MaterializationHelper.CreateNullableItemMaterializerMethodInfo.MakeGenericMethod( elementType.GetGenericArguments()[0]) : MaterializationHelper.CreateItemMaterializerMethodInfo.MakeGenericMethod(elementType); var itemMaterializer = itemMaterializerFactoryMethod.Invoke( null, new object[] { materializationInfo.Expression, itemProjector.AggregateType }); Expression <Func <Session, int, MaterializationContext> > materializationContextCtor = (s, entityCount) => new MaterializationContext(s, entityCount); var materializationContextExpression = materializationContextCtor .BindParameters(session, Expression.Constant(materializationInfo.EntitiesInRow)); Expression body = Expression.Call( materializeMethod, tupleReader, materializationContextExpression, parameterContext, Expression.Constant(itemMaterializer)); var projectorExpression = FastExpression.Lambda <Func <RecordSetReader, Session, ParameterContext, object> >( body, tupleReader, session, parameterContext); return(new Materializer(projectorExpression.CachingCompile())); }
public override Expression <Func <IEnumerable <Tuple> > > GetEnumerable() { var call = Expression.Call(Expression.Constant(enumerableFunc.Target), enumerableFunc.Method); MethodInfo selectMethod = WellKnownMembers.Enumerable.Select.MakeGenericMethod(typeof(TItem), typeof(Tuple)); var select = Expression.Call(selectMethod, call, Expression.Constant(converter)); return(FastExpression.Lambda <Func <IEnumerable <Tuple> > >(select)); }
public static LambdaExpression MakeLambda(Expression expression, TranslatorContext context) { var tupleParameter = Expression.Parameter(typeof(Tuple), "tuple"); var visitor = new ExpressionMaterializer(tupleParameter, context, null, EnumerableUtils <Parameter <Tuple> > .Empty); var processedExpression = OwnerRemover.RemoveOwner(expression); return(FastExpression.Lambda(visitor.Visit(processedExpression), tupleParameter)); }
private static T Evaluate <T>(Expression expression) { if (expression.NodeType == ExpressionType.Constant) { return((T)((ConstantExpression)expression).Value); } return(FastExpression.Lambda <Func <T> >(expression).CachingCompile().Invoke()); }
public override Expression <Func <ParameterContext, IEnumerable <Tuple> > > GetEnumerable() { var paramContext = Expression.Parameter(WellKnownOrmTypes.ParameterContext, "context"); var call = Expression.Call(Expression.Constant(enumerableFunc.Target), enumerableFunc.Method, paramContext); var selectMethod = WellKnownMembers.Enumerable.Select.MakeGenericMethod(typeof(TItem), WellKnownOrmTypes.Tuple); var select = Expression.Call(selectMethod, call, Expression.Constant(converter)); return(FastExpression.Lambda <Func <ParameterContext, IEnumerable <Tuple> > >(select, paramContext)); }
public Expression <Func <Tuple, Tuple, bool> > Rewrite(Expression <Func <Tuple, bool> > predicate, ColumnCollection predicateColumns, ColumnCollection currentColumns) { Initialize(predicate, predicateColumns, currentColumns); leftTupleParameter = Expression.Parameter(typeof(Tuple), "leftTuple"); var visited = Visit(predicate.Body); return((Expression <Func <Tuple, Tuple, bool> >)FastExpression .Lambda(visited, leftTupleParameter, predicate.Parameters[0])); }
private MappingEntry CreateMappingEntry(Expression expression) { var tupleAccess = expression.StripCasts().AsTupleAccess(); if (tupleAccess != null) { return(new MappingEntry(tupleAccess.GetTupleAccessArgument())); } return(new MappingEntry(FastExpression.Lambda(expression, calculatedColumnParameter))); }
public Expression <Func <Tuple, bool> > CreatePredicatesConjunction( Expression <Func <Tuple, bool> > newPredicate, Expression <Func <Tuple, bool> > oldPredicate) { var oldParameter = oldPredicate.Parameters[0]; var newParameter = newPredicate.Parameters[0]; var result = (Expression <Func <Tuple, bool> >)parameterRewriter .Replace(oldPredicate, oldParameter, newParameter); return((Expression <Func <Tuple, bool> >)FastExpression.Lambda(Expression .AndAlso(result.Body, newPredicate.Body), newParameter)); }
public Expression <Func <ParameterContext, T> > BindToParameterContext(Expression parameterExpression) { var body = Visit(parameterExpression); var resultType = typeof(T); if (resultType != body.Type) { body = Expression.Convert(body, resultType); } return(FastExpression.Lambda <Func <ParameterContext, T> >(body, parameterContextArgument)); }
public static MaterializationInfo MakeMaterialization(ItemProjectorExpression projector, TranslatorContext context, IEnumerable <Parameter <Tuple> > tupleParameters) { var tupleParameter = Expression.Parameter(typeof(Tuple), "tuple"); var materializationContextParameter = Expression.Parameter(typeof(ItemMaterializationContext), "mc"); var visitor = new ExpressionMaterializer(tupleParameter, context, materializationContextParameter, tupleParameters); var lambda = FastExpression.Lambda(visitor.Visit(projector.Item), tupleParameter, materializationContextParameter); var count = visitor.entityRegistry.Count; return(new MaterializationInfo(count, lambda)); }
private static Expression <Func <IEnumerable <Tuple> > > RemapRawProviderSource(Expression <Func <IEnumerable <Tuple> > > source, MapTransform mappingTransform) { var selectMethodInfo = typeof(Enumerable) .GetMethods() .Single(methodInfo => methodInfo.Name == "Select" && methodInfo.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Func <,>)) .MakeGenericMethod(typeof(Tuple), typeof(Tuple)); Func <Tuple, Tuple> selector = tuple => mappingTransform.Apply(TupleTransformType.Auto, tuple); var newExpression = Expression.Call(selectMethodInfo, source.Body, Expression.Constant(selector)); return((Expression <Func <IEnumerable <Tuple> > >)FastExpression.Lambda(newExpression)); }
public static void BuildFilter(IndexInfo index) { ArgumentValidator.EnsureArgumentNotNull(index, "index"); var parameter = Expression.Parameter(WellKnownOrmTypes.Tuple, "tuple"); var builder = new PartialIndexFilterBuilder(index, parameter); var body = builder.Visit(index.FilterExpression.Body); var filter = new PartialIndexFilterInfo { Expression = FastExpression.Lambda(body, parameter), Fields = builder.usedFields, }; index.Filter = filter; }
private Expression VisitQuerySingle(MethodCallExpression mc) { var returnType = mc.Method.ReturnType; var argument = mc.Arguments[0]; var queryAll = Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(returnType)); var source = ConstructQueryable(queryAll); var parameter = Expression.Parameter(returnType, "entity"); var keyAccessor = Expression.MakeMemberAccess(parameter, WellKnownMembers.IEntityKey); var equility = Expression.Equal(keyAccessor, argument); var lambda = FastExpression.Lambda(equility, parameter); return(VisitFirstSingle(source, lambda, mc.Method, false)); }
public IQueryable SelectPropertySwitchingToGeneric(IQueryable queryable, string propertyName) { Type entityType = queryable.ElementType; var propertyInfo = entityType.GetProperty(propertyName); var parameter = Expression.Parameter(entityType, "paramName"); var body = Expression.MakeMemberAccess(parameter, propertyInfo); var lambda = FastExpression.Lambda(body, parameter); // paramName=>paramName.Name var getPropertyValuesMethodInfo = typeof(MiscTest).GetMethod("SelectPropertyGeneric"); var genericMethod = getPropertyValuesMethodInfo.MakeGenericMethod(entityType, propertyInfo.PropertyType); return((IQueryable)genericMethod.Invoke(null, new object[] { queryable, lambda })); }
private Func <IEnumerable <Tuple>, Session, Dictionary <Parameter <Tuple>, Tuple>, ParameterContext, TResult> BuildMaterializer <TResult>( ProjectionExpression projection, IEnumerable <Parameter <Tuple> > tupleParameters) { var rs = Expression.Parameter(typeof(IEnumerable <Tuple>), "rs"); var session = Expression.Parameter(typeof(Session), "session"); var tupleParameterBindings = Expression.Parameter(typeof(Dictionary <Parameter <Tuple>, Tuple>), "tupleParameterBindings"); var parameterContext = Expression.Parameter(typeof(ParameterContext), "parameterContext"); var itemProjector = projection.ItemProjector; var materializationInfo = itemProjector.Materialize(context, tupleParameters); var elementType = itemProjector.Item.Type; var materializeMethod = MaterializationHelper.MaterializeMethodInfo .MakeGenericMethod(elementType); var compileMaterializerMethod = MaterializationHelper.CompileItemMaterializerMethodInfo .MakeGenericMethod(elementType); var itemMaterializer = compileMaterializerMethod.Invoke(null, new[] { materializationInfo.Expression }); Expression <Func <Session, int, MaterializationContext> > materializationContextCtor = (s, n) => new MaterializationContext(s, n); var materializationContextExpression = materializationContextCtor .BindParameters( session, Expression.Constant(materializationInfo.EntitiesInRow)); Expression body = Expression.Call( materializeMethod, rs, materializationContextExpression, parameterContext, Expression.Constant(itemMaterializer), tupleParameterBindings); if (projection.IsScalar) { var scalarMethodName = projection.ResultType.ToString(); var enumerableMethod = typeof(Enumerable) .GetMethods(BindingFlags.Static | BindingFlags.Public) .First(m => m.Name == scalarMethodName && m.GetParameters().Length == 1) .MakeGenericMethod(elementType); body = Expression.Call(enumerableMethod, body); } body = body.Type == typeof(TResult) ? body : Expression.Convert(body, typeof(TResult)); var projectorExpression = FastExpression.Lambda <Func <IEnumerable <Tuple>, Session, Dictionary <Parameter <Tuple>, Tuple>, ParameterContext, TResult> >(body, rs, session, tupleParameterBindings, parameterContext); return(projectorExpression.CachingCompile()); }
public void AddValues() { foreach (SetDescriptor descriptor in Descriptors) { var addContext = new AddValueContext { Descriptor = descriptor, Lambda = FastExpression.Lambda( WellKnownMembers.FuncOfTArgTResultType.MakeGenericType(typeof(T), descriptor.Expression.Type), descriptor.Expression, descriptor.Parameter), Statement = Statement }; descriptor.Expression.Visit( delegate(ParameterExpression p) { // ReSharper disable AccessToModifiedClosure if (p == descriptor.Parameter) { // ReSharper restore AccessToModifiedClosure addContext.EntityParamExists = true; } return(p); }); addContext.SubqueryExists = descriptor.Expression.IsContainsQuery(); addContext.Field = descriptor.Field; if (addContext.Field.IsEntitySet) { throw new NotSupportedException("EntitySets are not supported"); } if (addContext.Field.IsEntity) { AddEntityValue(addContext); continue; } if (!addContext.EntityParamExists && addContext.SubqueryExists) { AddComputedStaticExpression(addContext); } else if (addContext.EntityParamExists || addContext.SubqueryExists) { AddComputedExpression(addContext); } else { AddConstantValue(addContext); } } }
/// <summary> /// Extracts the parameter. /// </summary> /// <param name="expression">The expression.</param> public Expression <Func <T> > ExtractParameter <T>(Expression expression) { if (expression.NodeType == ExpressionType.Lambda) { return((Expression <Func <T> >)expression); } Type type = expression.Type; if (type.IsValueType) { expression = Expression.Convert(expression, typeof(T)); } var lambda = FastExpression.Lambda <Func <T> >(expression); return(lambda); }
public static bool TryRewrite(LambdaExpression resultSelector, ParameterExpression sourceParameter, ParameterExpression targetParameter, out LambdaExpression result) { var parameters = resultSelector.Parameters .Select(p => p == sourceParameter ? targetParameter : p) .ToArray(); var rewriter = new SelectManySelectorRewriter(sourceParameter, targetParameter); var body = rewriter.Visit(resultSelector.Body); if (rewriter.processingFailed) { result = null; return(false); } result = FastExpression.Lambda(body, parameters); return(true); }
private void AddConstantValue(AddValueContext addContext) { SqlTableColumn column = SqlDml.TableColumn(addContext.Statement.Table, addContext.Field.Column.Name); SqlExpression value; object constant = FastExpression.Lambda(addContext.Lambda.Body).Compile().DynamicInvoke(); if (constant == null) { value = SqlDml.Null; } else { QueryParameterBinding binding = parent.QueryBuilder.CreateParameterBinding(constant.GetType(), context => constant); parent.Bindings.Add(binding); value = binding.ParameterReference; } addContext.Statement.AddValue(column, value); }
/// <summary> /// Strips <see cref="Expression.Quote"/> expressions. /// </summary> /// <param name="expression">The expression.</param> public static LambdaExpression StripQuotes(this Expression expression) { while (expression.NodeType == ExpressionType.Quote) { expression = ((UnaryExpression)expression).Operand; } var lambda = expression as LambdaExpression; if (lambda == null) { if (!typeof(LambdaExpression).IsAssignableFrom(expression.Type)) { throw new InvalidOperationException(string.Format("Unable to process expression '{0}'", expression)); } var typeAs = Expression.TypeAs(expression, typeof(LambdaExpression)); return(FastExpression.Lambda <Func <LambdaExpression> >(typeAs).CachingCompile()()); } return(lambda); }
public static LambdaExpression Execute(LambdaExpression expression) { // Transform lamba expression as follows: // if original lambda contains sequence of reference field traversals, // extract this traversal sequence and create lambda with it as body, otherwise return null. // Longest possible expression is returned. // Example 1: e => e.Ref.Value > 0 transforms into e => e.Foo // Example 2: e => e.Value transforms into null // Example 3: e => e.Ref1.Ref2!=null transforms into e => e.Ref1.Ref var extractor = new ReferenceFieldAccessExtractor(); extractor.parameter = expression.Parameters[0]; extractor.Visit(expression); return(extractor.result == null ? null : FastExpression.Lambda(extractor.result, extractor.parameter)); }
/// <summary> /// Evaluates the specified <paramref name="e"/> into <see cref="ConstantExpression"/>. /// </summary> /// <param name="e">The expression.</param> public static ConstantExpression Evaluate(Expression e) { if (e == null) { return(null); } if (e.NodeType == ExpressionType.Constant) { return((ConstantExpression)e); } Type type = e.Type; if (type.IsValueType) { e = Expression.Convert(e, typeof(object)); } var lambda = FastExpression.Lambda <Func <object> >(e); var func = lambda.CachingCompile(); return(Expression.Constant(func(), type)); }
public IQueryable SelectPropertyBuildingExpression(IQueryable queryable, string propertyName) { Type entityType = queryable.ElementType; var propertyInfo = entityType.GetProperty(propertyName); var queryAllExpression = Expression.Constant(queryable); var selectMethodInfo = typeof(System.Linq.Queryable).GetMethods() .Single(methodInfo => methodInfo.Name == Xtensive.Reflection.WellKnown.Queryable.Select && methodInfo.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericArguments().Length == 2); var parameter = Expression.Parameter(entityType, "paramName"); var body = Expression.MakeMemberAccess(parameter, propertyInfo); var lambda = FastExpression.Lambda(body, parameter); // paramName=>paramName.Name var genericSelectMethodInfo = selectMethodInfo.MakeGenericMethod(entityType, propertyInfo.PropertyType); var selectExpression = Expression.Call(genericSelectMethodInfo, queryAllExpression, lambda); return((IQueryable)FastExpression .Lambda(selectExpression, EnumerableUtils <ParameterExpression> .Empty) .Compile() .DynamicInvoke()); }
private static void AddGroupByItemWrapper(GroupByQuery groupBy, List <LambdaExpression> elementProjections) { var keySelector = groupBy.KeySelector; var elementSelector = groupBy.ElementSelector; var keyType = keySelector.Body.Type; var elementType = elementSelector.Body.Type; var wrapperType = typeof(GroupByItemWrapper <,>).MakeGenericType(keyType, elementType); var wrapperKeyProperty = wrapperType.GetProperty("Key"); var wrapperElementProperty = wrapperType.GetProperty("Element"); var projectionParameter = keySelector.Parameters[0]; var projectionLambda = FastExpression.Lambda( Expression.MemberInit( Expression.New(wrapperType), Expression.Bind(wrapperKeyProperty, keySelector.Body), Expression.Bind(wrapperElementProperty, elementSelector.BindParameters(projectionParameter))), projectionParameter); groupBy.Source = QueryFactory.Select(groupBy.Source, projectionLambda); var wrapperParameter = Expression.Parameter(wrapperType, "wrapper"); var wrapperKeyAccess = Expression.MakeMemberAccess(wrapperParameter, wrapperKeyProperty); var wrapperElementAccess = Expression.MakeMemberAccess(wrapperParameter, wrapperElementProperty); groupBy.KeySelector = FastExpression.Lambda(wrapperKeyAccess, wrapperParameter); groupBy.ElementSelector = FastExpression.Lambda(wrapperElementAccess, wrapperParameter); for (int i = 0; i < elementProjections.Count; i++) { elementProjections[i] = FastExpression.Lambda( elementProjections[i].BindParameters(wrapperElementAccess), wrapperParameter); } }
internal static object Invoke(this Expression expression) { return(FastExpression.Lambda(typeof(Func <>).MakeGenericType(expression.Type), expression).Compile().DynamicInvoke()); }
private void AddEntityValue(AddValueContext addContext) { if (addContext.EntityParamExists) { throw new NotSupportedException("Expressions with reference to updating entity are not supported"); } var methodCall = addContext.Descriptor.Expression as MethodCallExpression; int i; if (methodCall != null) { if (methodCall.Method.DeclaringType == typeof(QueryEndpoint) && methodCall.Method.Name.In("Single", "SingleOrDefault")) { object[] keys; if (methodCall.Arguments[0].Type == typeof(Key) || methodCall.Arguments[0].Type.IsSubclassOf(typeof(Key))) { var key = (Key)methodCall.Arguments[0].Invoke(); keys = new object[key.Value.Count]; for (i = 0; i < keys.Length; i++) { keys[i] = key.Value.GetValue(i); } } else { keys = (object[])methodCall.Arguments[0].Invoke(); } i = -1; foreach (ColumnInfo column in addContext.Field.Columns) { i++; SqlExpression value; if (keys[i] == null) { value = SqlDml.Null; } else { object v = keys[i]; QueryParameterBinding binding = parent.QueryBuilder.CreateParameterBinding(v.GetType(), context => v); parent.Bindings.Add(binding); value = binding.ParameterReference; } SqlTableColumn c = SqlDml.TableColumn(addContext.Statement.Table, column.Name); addContext.Statement.AddValue(c, value); } return; } if (methodCall.Method.DeclaringType == typeof(Queryable) && methodCall.Method.Name.In("Single", "SingleOrDefault", "First", "FirstOrDefault")) { Expression exp = methodCall.Arguments[0]; TypeInfo info = parent.GetTypeInfo(addContext.Field.ValueType); if (methodCall.Arguments.Count == 2) { exp = Expression.Call( typeof(Queryable), "Where", new[] { info.UnderlyingType }, exp, methodCall.Arguments[1]); } exp = Expression.Call(typeof(Queryable), "Take", new[] { info.UnderlyingType }, exp, Expression.Constant(1)); i = -1; foreach (FieldInfo field in info.Key.Fields) { i++; ParameterExpression p = Expression.Parameter(info.UnderlyingType); LambdaExpression lambda = FastExpression.Lambda( WellKnownMembers.FuncOfTArgTResultType.MakeGenericType(info.UnderlyingType, field.ValueType), Expression.MakeMemberAccess(p, field.UnderlyingProperty), p); IQueryable q = ((IQueryProvider)parent.QueryProvider).CreateQuery( Expression.Call(typeof(Queryable), "Select", new[] { info.UnderlyingType, field.ValueType }, exp, lambda)); QueryTranslationResult request = parent.GetRequest(field.ValueType, q); parent.Bindings.AddRange(request.ParameterBindings); SqlTableColumn c = SqlDml.TableColumn(addContext.Statement.Table, addContext.Field.Columns[i].Name); addContext.Statement.AddValue(c, SqlDml.SubQuery((ISqlQueryExpression)request.Query)); } return; } } i = -1; var entity = (IEntity)FastExpression.Lambda(addContext.Lambda.Body).Compile().DynamicInvoke(); foreach (ColumnInfo column in addContext.Field.Columns) { i++; SqlExpression value; if (entity == null) { value = SqlDml.Null; } else { object v = entity.Key.Value.GetValue(i); QueryParameterBinding binding = parent.QueryBuilder.CreateParameterBinding(v.GetType(), context => v); parent.Bindings.Add(binding); value = binding.ParameterReference; } SqlTableColumn c = SqlDml.TableColumn(addContext.Statement.Table, column.Name); addContext.Statement.AddValue(c, value); } }
internal static object Invoke(this Expression expression) { return(FastExpression.Lambda( WellKnownMembers.FuncOfTResultType.MakeGenericType(expression.Type), expression).Compile().DynamicInvoke()); }
public static Expression CreateEntitySetQuery(Expression ownerEntity, FieldInfo field) { if (!field.IsDynamicallyDefined && !field.UnderlyingProperty.PropertyType.IsOfGenericType(WellKnownOrmTypes.EntitySetOfT)) { throw Exceptions.InternalError(Strings.ExFieldMustBeOfEntitySetType, OrmLog.Instance); } if (field.IsDynamicallyDefined && !field.ValueType.IsOfGenericType(WellKnownOrmTypes.EntitySetOfT)) { throw Exceptions.InternalError(Strings.ExFieldMustBeOfEntitySetType, OrmLog.Instance); } var elementType = field.ItemType; var association = field.Associations.Last(); if (association.Multiplicity == Multiplicity.OneToMany) { var targetField = association.TargetType.Fields[association.Reversed.OwnerField.Name]; var whereParameter = Expression.Parameter(elementType, "p"); var expression = BuildExpressionForFieldRecursivly(targetField, whereParameter); var whereExpression = Expression.Equal( Expression.Property( expression, WellKnownMembers.IEntityKey), Expression.Property( ownerEntity, WellKnownMembers.IEntityKey) ); return(Expression.Call( WellKnownMembers.Queryable.Where.MakeGenericMethod(elementType), CreateEntityQuery(elementType), FastExpression.Lambda(whereExpression, whereParameter) )); } var connectorType = association.AuxiliaryType.UnderlyingType; var referencingField = association.IsMaster ? association.AuxiliaryType.Fields[WellKnown.SlaveFieldName] : association.AuxiliaryType.Fields[WellKnown.MasterFieldName]; var referencedField = association.IsMaster ? association.AuxiliaryType.Fields[WellKnown.MasterFieldName] : association.AuxiliaryType.Fields[WellKnown.SlaveFieldName]; var filterParameter = Expression.Parameter(connectorType, "t"); var filterExpression = Expression.Equal( Expression.MakeMemberAccess( Expression.MakeMemberAccess(filterParameter, referencedField.UnderlyingProperty), WellKnownMembers.IEntityKey), Expression.MakeMemberAccess( ownerEntity, WellKnownMembers.IEntityKey) ); var outerQuery = Expression.Call( WellKnownMembers.Queryable.Where.MakeGenericMethod(connectorType), CreateEntityQuery(connectorType), FastExpression.Lambda(filterExpression, filterParameter) ); var outerSelectorParameter = Expression.Parameter(connectorType, "o"); var outerSelector = FastExpression.Lambda( Expression.MakeMemberAccess(outerSelectorParameter, referencingField.UnderlyingProperty), outerSelectorParameter); var innerSelectorParameter = Expression.Parameter(elementType, "i"); var innerSelector = FastExpression.Lambda(innerSelectorParameter, innerSelectorParameter); var resultSelector = FastExpression.Lambda(innerSelectorParameter, outerSelectorParameter, innerSelectorParameter); var innerQuery = CreateEntityQuery(elementType); var joinMethodInfo = WellKnownTypes.Queryable.GetMethods() .Single(mi => mi.Name == Xtensive.Reflection.WellKnown.Queryable.Join && mi.IsGenericMethod && mi.GetParameters().Length == 5) .MakeGenericMethod(new[] { connectorType, elementType, outerSelector.Body.Type, resultSelector.Body.Type }); return(Expression.Call(joinMethodInfo, outerQuery, innerQuery, outerSelector, innerSelector, resultSelector)); }