private static void SetFieldByKeys <TParent, TChild>( PropertyAccessor <TParent, TChild> schema, IList <TParent> parentEntities, IList <TChild> childEntities) where TParent : class where TChild : class { var predicate = schema.AssociationDescriptor.GetPredicate(typeof(TParent), typeof(TChild)) as Expression <Func <TParent, TChild, bool> >; if (predicate == null) { predicate = (p, o) => true; } var keyTuple = EntityMatchWalker.ExtractKeyNodes(predicate, predicate.Parameters[0], predicate.Parameters[1]); var thisKeyExpressions = keyTuple.Item1; var otherKeyExpressions = keyTuple.Item2; var otherKeys = KeyExpressionsToKeyHolder(schema.AssociationDescriptor.OtherKey, otherKeyExpressions); var thisKeys = KeyExpressionsToKeyHolder(schema.AssociationDescriptor.ThisKey, thisKeyExpressions); if (otherKeys.Any() && thisKeys.Any()) { var hasher = _fkHashFuncs.GetOrAdd(new FKHashFuncKey { OtherType = typeof(TChild), OtherKeys = otherKeys.ToList(), ThisType = typeof(TParent), ThisKeys = thisKeys.ToList() }, k => new FKHashCodeFunc <TParent, TChild>(CreateGetHashCodeFunc <TParent>(thisKeys), CreateGetHashCodeFunc <TChild>(otherKeys), predicate.Compile())); var typeHasher = hasher as FKHashCodeFunc <TParent, TChild>; var childLookup = childEntities.ToLookup(typeHasher.OtherHashCodeFunc); MatchEntityLookup(schema, parentEntities, typeHasher.AssociationPredicate, childLookup, typeHasher.ThisHashCodeFunc); } else { MatchEntityList(schema, parentEntities, childEntities, predicate.Compile()); } }
internal static IQueryable <TChild> BuildReusableQueryableForProperty <TParent, TChild>( IQueryable <TParent> mainQuery, PropertyAccessor <TParent, TChild> schema) where TParent : class where TChild : class { if (schema.IsMemberEntityTypeIEnumerable) { throw new ArgumentException($"'{nameof(TChild)}' cannot be an IEnumerable<>."); } var mainQueryCopy = mainQuery; var db = mainQuery.GetDataContext <IDataContext>(); //join the query passed in to the child table var joinExpr = BuildJoinExpression(schema); var subSelect = db.GetTable <TChild>().Join(mainQueryCopy, SqlJoinType.Inner, joinExpr, (c, p) => c); return(subSelect); }
private static Expression BuildJoinClauseByForeignKey <TParent, TChild>( PropertyAccessor <TParent, TChild> schema, LambdaExpression predicate, ParameterExpression parentParam, ParameterExpression childParam) where TParent : class where TChild : class { var assoc = schema.AssociationDescriptor; Expression previousExpr = predicate == null ? null : SubstituteParameters(predicate, parentParam, childParam); if (previousExpr is LambdaExpression lambdaExpression) { previousExpr = lambdaExpression.Body; } for (int i = 0; i < assoc.ThisKey.Length; i++) { Expression childProperty = Expression.Property(childParam, assoc.OtherKey[i]); Expression parentProperty = Expression.Property(parentParam, assoc.ThisKey[i]); if (childProperty.Type != parentProperty.Type) { parentProperty = Expression.Convert(parentProperty, childProperty.Type); } var equals = Expression.Equal(parentProperty, childProperty); if (previousExpr == null) { previousExpr = equals; } else { previousExpr = Expression.AndAlso(previousExpr, equals); } } return(previousExpr); }
private static void MatchEntityLookup <TParent, TChild>(PropertyAccessor <TParent, TChild> schema, IList <TParent> parentEntities, Func <TParent, TChild, bool> predicateFunc, ILookup <int, TChild> childLookup, Func <TParent, int> parentHasher) where TParent : class where TChild : class { if (schema.IsMemberTypeIEnumerable) { var setter = schema.DeclaringType.CreateCollectionPropertySetter <TParent, TChild>(schema.PropertyName, schema.MemberType); var ifnullSetter = schema.DeclaringType.CreatePropertySetup <TParent, TChild>(schema.PropertyName); foreach (var item in parentEntities) { ifnullSetter(item); foreach (var childEntity in childLookup[parentHasher(item)] .Where(x => predicateFunc(item, x))) { setter(item, childEntity); } } } else { var setter = schema.DeclaringType.CreatePropertySetter <TParent, TChild>(schema.PropertyName); foreach (var item in parentEntities) { var childEntity = childLookup[parentHasher(item)] .Where(x => predicateFunc(item, x)) .FirstOrDefault(); setter(item, childEntity); } } }
internal static Expression <Func <TChild, TParent, bool> > BuildJoinExpression <TParent, TChild>( PropertyAccessor <TParent, TChild> schema) where TParent : class where TChild : class { var predicate = schema.AssociationDescriptor.GetPredicate(schema.DeclaringType, schema.MemberEntityType); var parentParam = predicate?.Parameters.FirstOrDefault() ?? Expression.Parameter(schema.DeclaringType, "p"); var childParam = predicate?.Parameters.Skip(1).FirstOrDefault() ?? Expression.Parameter(schema.MemberEntityType, "c"); var previousExpr = BuildJoinClauseByForeignKey(schema, predicate, parentParam, childParam); if (previousExpr is LambdaExpression lambda) { previousExpr = lambda.Body; } var expr = Expression.Lambda <Func <TChild, TParent, bool> >(previousExpr, childParam, parentParam); return(expr); }
internal static IQueryable <TChild> BuildQueryableForProperty <TParent, TChild>(IQueryable <TParent> mainQuery, PropertyAccessor <TParent, TChild> schema) where TParent : class where TChild : class { if (schema.IsMemberEntityTypeIEnumerable) { throw new ArgumentException($"'{nameof(TChild)}' cannot be an IEnumerable<>."); } IQueryable mainQueryCopy = mainQuery; var db = mainQuery.GetDataContext <IDataContext>(); ParameterExpression parentParam = null; ParameterExpression childParam = null; //join the child table in the main section of the new to //the same table in the EXISTS function var predicate = schema.AssociationDescriptor .GetPredicate(schema.DeclaringType, schema.MemberEntityType); Expression innerCondition = null; Type innerWhereDelegate = null; Type outerWhereDelegate = null; Type innerWhereType = null; if (predicate != null) { parentParam = Expression.Parameter(schema.MemberEntityType, "parent"); childParam = Expression.Parameter(schema.MemberEntityType, "child"); innerWhereType = schema.MemberEntityType; innerWhereDelegate = typeof(Func <TChild, bool>); innerCondition = BuildJoinClauseByPrimaryKey(schema.ChildEntityDescriptor, parentParam, childParam); outerWhereDelegate = typeof(Func <TChild, bool>); var joinExpr = BuildJoinExpression(schema); var subSelect = db.GetTable <TChild>().Join(mainQuery, SqlJoinType.Inner, joinExpr, (c, p) => c); mainQueryCopy = subSelect; } else { parentParam = Expression.Parameter(schema.DeclaringType, "parent"); childParam = Expression.Parameter(schema.MemberEntityType, "child"); innerWhereType = schema.DeclaringType; innerWhereDelegate = typeof(Func <TParent, bool>); innerCondition = BuildJoinClauseByForeignKey(schema, null, parentParam, childParam); outerWhereDelegate = typeof(Func <TChild, bool>); } // build theIQ.Where( pe2 => innerCondition ) var queryableType = typeof(Queryable); var innerWhere = Expression.Call( queryableType, nameof(Enumerable.Where), new Type[] { innerWhereType }, new Expression[] { mainQueryCopy.Expression, Expression.Lambda(innerWhereDelegate, innerCondition, new ParameterExpression[] { parentParam }) } ); // build x.Where( pe2 => innerWhere ).Any() var anyCall = Expression.Call( queryableType, nameof(Enumerable.Any), new Type[] { innerWhereType }, innerWhere ); var childTable = db.GetTable <TChild>(); // build x.Where( pe1 => anyCall ) var outerWhere = Expression.Call( queryableType, nameof(Enumerable.Where), new Type[] { schema.MemberEntityType }, new Expression[] { childTable.Expression, Expression.Lambda(outerWhereDelegate, anyCall, new ParameterExpression[] { childParam }) } ); var resultingQuery = Linq.Internals.CreateExpressionQueryInstance <TChild>(db, outerWhere); return(resultingQuery); }