Пример #1
0
        public static ISpecification <TRight> Combine <TLeft, TRight>(this ISpecification <TLeft> specification, ISpecification <TRight> other)
        {
            var leftQuery  = (Query.Query)specification.Query;
            var rightQuery = (Query.Query)other.Query;

            var rightQueryItems  = GetQueryChain(rightQuery);
            var rightFirstClause = rightQueryItems[0];

            if (leftQuery.Parameters.OutType != rightFirstClause.Parameters.InType)
            {
                throw new InvalidOperationException($"Left specification provide type {leftQuery.Parameters.OutType} that did not match right specification {rightFirstClause.Parameters.InType}");
            }

            var query = leftQuery;

            foreach (var itm in rightQueryItems)
            {
                if (itm.Parameters.QueryType == QueryType.Empty)
                {
                    continue;
                }

                query = new Query.Query(query, itm.Parameters, itm.EntityType);
            }

            return(new CustomSpecification <TRight>(query));
        }
Пример #2
0
        static Query.Query[] GetQueryChain(this Query.Query query)
        {
            var chain = new List <Query.Query>();

            while (query != null)
            {
                chain.Add(query);
                query = query.Parent;
            }

            chain.Reverse();
            return(chain.ToArray());
        }
Пример #3
0
        public static ISpecification <T> Or <T>(this ISpecification <T> left, ISpecification <T> right)
        {
            var leftQuery  = (Query.Query)left.Query;
            var rightQuery = (Query.Query)right.Query;

            var leftQueryItems  = GetQueryChain(leftQuery);
            var rightQueryItems = GetQueryChain(rightQuery);

            leftQuery  = leftQueryItems.Last();
            rightQuery = rightQueryItems.SkipWhile(x => x.Parameters.QueryType == QueryType.Empty).First();

            if (leftQueryItems.Last().Parameters.QueryType != QueryType.Where)
            {
                throw new InvalidOperationException("Left specification must ending with Where expression");
            }

            if (rightQueryItems.SkipWhile(x => x.Parameters.QueryType == QueryType.Empty).Count(x => x.Parameters.QueryType != QueryType.Where) > 0)
            {
                throw new InvalidOperationException("Right specification should contains only one Where clause");
            }

            var argumentParameter = Expression.Parameter(typeof(T), "obj");
            var contextParameter  = Expression.Parameter(typeof(IQueryContext), "context");

            var leftExpression     = (LambdaExpression)leftQuery.Parameters.Expression;
            var leftPartExpression = new ReplaceExpressionVisitor <ParameterExpression, ParameterExpression>(
                new ReplaceItem <ParameterExpression, ParameterExpression>(leftExpression.Parameters.First(x => x.Type == typeof(T)), argumentParameter),
                new ReplaceItem <ParameterExpression, ParameterExpression>(leftExpression.Parameters.FirstOrDefault(x => x.Type == typeof(IQueryContext)), contextParameter))
                                     .Visit(leftExpression.Body);

            var rightExpression     = (LambdaExpression)rightQuery.Parameters.Expression;
            var rightPartExpression = new ReplaceExpressionVisitor <ParameterExpression, ParameterExpression>(
                new ReplaceItem <ParameterExpression, ParameterExpression>(rightExpression.Parameters.First(x => x.Type == typeof(T)), argumentParameter),
                new ReplaceItem <ParameterExpression, ParameterExpression>(rightExpression.Parameters.FirstOrDefault(x => x.Type == typeof(IQueryContext)), contextParameter))
                                      .Visit(rightExpression.Body);

            var resultExpressionBody = Expression.OrElse(leftPartExpression, rightPartExpression);

            var query = new Query.Query(
                leftQueryItems.Last().Parent,
                new WhereQueryParameter(
                    typeof(T),
                    typeof(T),
                    Expression.Lambda(resultExpressionBody, argumentParameter, contextParameter),
                    QueryType.Where),
                leftQuery.EntityType);

            return(new CustomSpecification <T>(query));
        }