示例#1
0
        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);
        }
示例#4
0
        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);
        }