Пример #1
0
        /// <summary>
        ///     Creates a <see cref="IProjection" /> for the given <see cref="Expression" />.
        /// </summary>
        /// <param name="expression">
        ///     The expression.
        /// </param>
        /// <param name="context">
        ///     The context for the projection.
        /// </param>
        /// <returns>
        ///     The resolved <see cref="IProjection" /> instance.
        /// </returns>
        /// <exception cref="NotSupportedException">
        ///     The <see cref="Expression" /> could not be resolved as it may contain unsupported features or similar.
        /// </exception>
        public static IProjection GetProjection
        (
            Expression expression,
            HelperContext context
        )
        {
            IEnumerable <IExpressionHandler> handlers = FlowQueryHelper
                                                        .GetExpressionHandlers(expression.NodeType)
                                                        .Where(x => x.CanHandleProjectionOf(expression, context))
                                                        .ToArray();

            if (handlers.Any())
            {
                return(GetProjectionUsing(handlers, expression, context));
            }

            if (expression.NodeType == ExpressionType.Parameter && expression.ToString() == context.RootAlias)
            {
                throw new NotSupportedException
                      (
                          "Unable to select the root entity like 'x => x', select without an expression instead"
                      );
            }

            return(GetValueProjection(expression));
        }
Пример #2
0
        /// <summary>
        ///     Creates a <see cref="ICriterion" /> for the given <see cref="Expression" />.
        /// </summary>
        /// <param name="expression">
        ///     The expression.
        /// </param>
        /// <param name="context">
        ///     The helper context.
        /// </param>
        /// <returns>
        ///     The created <see cref="ICriterion" />.
        /// </returns>
        public static ICriterion GetCriterion(Expression expression, HelperContext context)
        {
            switch (expression.NodeType)
            {
            case ExpressionType.AndAlso:
            case ExpressionType.OrElse:
            case ExpressionType.ExclusiveOr:
            case ExpressionType.Equal:
            case ExpressionType.NotEqual:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
                return(GetCriterionForBinary(expression as BinaryExpression, context));

            case ExpressionType.Call:
                return(GetCriterionForMethodCall(expression as MethodCallExpression, context));

            case ExpressionType.Lambda:
                return(GetCriterion(((LambdaExpression)expression).Body, context));

            case ExpressionType.Not:
                return(Restrictions.Not(GetCriterion(((UnaryExpression)expression).Operand, context)));

            case ExpressionType.MemberAccess:
                return(Restrictions.Eq(ExpressionHelper.GetPropertyName(expression, context.RootAlias), true));

            case ExpressionType.Invoke:
                return(GetCriterionForInvoke(expression as InvocationExpression, context));

            default:
                return(Restrictions.Eq(Projections.Constant(ExpressionHelper.GetValue <bool>(expression)), true));
            }
        }
Пример #3
0
        /// <summary>
        ///     Creates a <see cref="ICriterion" /> for a binary operation.
        /// </summary>
        /// <param name="a">
        ///     Expression A.
        /// </param>
        /// <param name="b">
        ///     Expression B.
        /// </param>
        /// <param name="type">
        ///     The operation type.
        /// </param>
        /// <param name="context">
        ///     The helper context.
        /// </param>
        /// <returns>
        ///     The created <see cref="ICriterion" />.
        /// </returns>
        public static ICriterion GetCriterionForBinary
        (
            Expression a,
            Expression b,
            ExpressionType type,
            HelperContext context
        )
        {
            if (a.NodeType == ExpressionType.Convert)
            {
                return(GetCriterionForBinary(((UnaryExpression)a).Operand, b, type, context));
            }

            if (b.NodeType == ExpressionType.Convert)
            {
                return(GetCriterionForBinary(a, ((UnaryExpression)b).Operand, type, context));
            }

            switch (type)
            {
            case ExpressionType.AndAlso:
                return(Restrictions.And(GetCriterion(a, context), GetCriterion(b, context)));

            case ExpressionType.OrElse:
                return(Restrictions.Or(GetCriterion(a, context), GetCriterion(b, context)));

            case ExpressionType.ExclusiveOr:

                ICriterion criterionA = GetCriterion(a, context);
                ICriterion criterionB = GetCriterion(b, context);

                return(Restrictions
                       .Or
                       (
                           Restrictions.And(criterionA, Restrictions.Not(criterionB)),
                           Restrictions.And(criterionB, Restrictions.Not(criterionA))
                       ));
            }

            bool isProjectedA = IsProjected(a, context);
            bool isProjectedB = IsProjected(b, context);

            // Projection-Projection
            if (isProjectedA && isProjectedB)
            {
                return(GetProjectionProjectionCriterion
                       (
                           ProjectionHelper.GetProjection(a, context),
                           ProjectionHelper.GetProjection(b, context),
                           type
                       ));
            }

            if (isProjectedA || !isProjectedB)
            {
                return(GetProjectionValueCriterion(a, ExpressionHelper.GetValue(b), type, context, false));
            }

            return(GetProjectionValueCriterion(b, ExpressionHelper.GetValue(a), type, context, true));
        }
Пример #4
0
        /// <summary>
        ///     Determines whether the given <see cref="Expression" /> is projected.
        /// </summary>
        /// <param name="expression">
        ///     The expression.
        /// </param>
        /// <param name="context">
        ///     The helper context.
        /// </param>
        /// <returns>
        ///     True if the <see cref="Expression" /> is considered to be projected; false otherwise.
        /// </returns>
        public static bool IsProjected(Expression expression, HelperContext context)
        {
            string expressionRoot = ExpressionHelper.GetRoot(expression);

            return(expression is BinaryExpression ||
                   (expressionRoot != null &&
                    (expressionRoot == context.RootAlias ||
                     context.Data.Aliases.ContainsValue(expressionRoot))));
        }
Пример #5
0
        /// <summary>
        ///     Creates a <see cref="IProjection" /> from the given <see cref="Expression" />.
        /// </summary>
        /// <param name="handlers">
        ///     The set of <see cref="IExpressionHandler" /> instances to use when resolving the
        ///     <see cref="IProjection" /> of the given <see cref="Expression" />.
        /// </param>
        /// <param name="expression">
        ///     The expression.
        /// </param>
        /// <param name="context">
        ///     The context for the projection.
        /// </param>
        /// <returns>
        ///     The created <see cref="IProjection" />.
        /// </returns>
        /// <exception cref="NotSupportedException">
        ///     The <see cref="Expression" /> could not be resolved as it may contain unsupported features or similar.
        /// </exception>
        private static IProjection GetProjectionUsing
        (
            IEnumerable <IExpressionHandler> handlers,
            Expression expression,
            HelperContext context
        )
        {
            foreach (IExpressionHandler handler in handlers)
            {
                IProjection projection = handler.Project(expression, context);

                if (projection != null)
                {
                    return(projection);
                }
            }

            throw new NotSupportedException(string.Format(NotSupportedMessage, expression));
        }
Пример #6
0
        /// <summary>
        ///     Creates a <see cref="ICriterion" /> for the given <see cref="InvocationExpression" />.
        /// </summary>
        /// <param name="expression">
        ///     The expression.
        /// </param>
        /// <param name="context">
        ///     The helper context.
        /// </param>
        /// <returns>
        ///     The created <see cref="ICriterion" />.
        /// </returns>
        public static ICriterion GetCriterionForInvoke
        (
            InvocationExpression expression,
            HelperContext context
        )
        {
            if (expression.Expression.Type == typeof(WhereDelegate))
            {
                string property = ExpressionHelper.GetPropertyName(expression.Arguments[0], context.RootAlias);

                var isExpression = ExpressionHelper.GetValue <IsExpression>(expression.Arguments[1]);

                ICriterion criterion = isExpression.Compile(property);

                return(criterion);
            }

            return(Restrictions.Eq(Projections.Constant(ExpressionHelper.GetValue <bool>(expression)), true));
        }
Пример #7
0
        /// <summary>
        ///     Gets the property name for the given <see cref="Expression" />.
        /// </summary>
        /// <param name="expression">
        ///     The expression.
        /// </param>
        /// <param name="expectedRoot">
        ///     The expected root.
        /// </param>
        /// <param name="isRooted">
        ///     Indicates whether the property is rooted on an alias or not.
        /// </param>
        /// <param name="context">
        ///     The <see cref="HelperContext" /> context, used only (and required) when <paramref name="isRooted" /> is
        ///     set to true.
        /// </param>
        /// <returns>
        ///     The property name.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="expression" /> is null.
        /// </exception>
        public static string GetPropertyName
        (
            Expression expression,
            string expectedRoot,
            bool isRooted         = false,
            HelperContext context = null
        )
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            string property = GetPropertyName(expression);

            string[] splits = property.Split('.');

            if (splits[0] == expectedRoot)
            {
                var parts = new string[splits.Length - 1];

                for (int i = 1; i < splits.Length; i++)
                {
                    parts[i - 1] = splits[i];
                }

                return(string.Join(".", parts));
            }

            if (isRooted && context != null && splits.Length >= 2)
            {
                string root = string.Join("_", splits.Take(splits.Length - 1));

                // only modify |property| if there is in fact an alias matching |root|.
                if (context.Data.Aliases.ContainsValue(root))
                {
                    property = root + "." + splits.Last();
                }
            }

            return(property);
        }
Пример #8
0
 /// <summary>
 ///     Creates a <see cref="ICriterion" /> for the given <see cref="BinaryExpression" />.
 /// </summary>
 /// <param name="expression">
 ///     The expression.
 /// </param>
 /// <param name="context">
 ///     The helper context.
 /// </param>
 /// <returns>
 ///     The created <see cref="ICriterion" />.
 /// </returns>
 public static ICriterion GetCriterionForBinary(BinaryExpression expression, HelperContext context)
 {
     return(GetCriterionForBinary(expression.Left, expression.Right, expression.NodeType, context));
 }
Пример #9
0
        /// <summary>
        ///     Creates <see cref="ICriterion" /> for a comparison between a value and a projection.
        /// </summary>
        /// <param name="expression">
        ///     The expression.
        /// </param>
        /// <param name="value">
        ///     The value.
        /// </param>
        /// <param name="type">
        ///     The comparison type.
        /// </param>
        /// <param name="context">
        ///     The helper context.
        /// </param>
        /// <param name="overTurned">
        ///     Indicates whether the comparison has been reversed to simplify other code.
        /// </param>
        /// <returns>
        ///     The created <see cref="ICriterion" />.
        /// </returns>
        /// <exception cref="NotSupportedException">
        ///     The <see cref="Expression" /> could not be resolved as it may contain unsupported features or similar.
        /// </exception>
        public static ICriterion GetProjectionValueCriterion
        (
            Expression expression,
            object value,
            ExpressionType type,
            HelperContext context,
            bool overTurned
        )
        {
            if (overTurned)
            {
                switch (type)
                {
                case ExpressionType.GreaterThan:
                    type = ExpressionType.LessThan;
                    break;

                case ExpressionType.GreaterThanOrEqual:
                    type = ExpressionType.LessThanOrEqual;
                    break;

                case ExpressionType.LessThan:
                    type = ExpressionType.GreaterThan;
                    break;

                case ExpressionType.LessThanOrEqual:
                    type = ExpressionType.GreaterThanOrEqual;
                    break;
                }
            }

            IProjection projection = ProjectionHelper.GetProjection(expression, context);

            switch (type)
            {
            case ExpressionType.Equal:

                if (value == null)
                {
                    return(Restrictions.IsNull(projection));
                }

                if (value is bool)
                {
                    return(GetCriterion((bool)value ? expression : Expression.Not(expression), context));
                }

                return(Restrictions.Eq(projection, value));

            case ExpressionType.NotEqual:

                if (value == null)
                {
                    return(Restrictions.IsNotNull(projection));
                }

                if (value is bool)
                {
                    return(GetCriterion(!(bool)value ? expression : Expression.Not(expression), context));
                }

                return(Restrictions.Not(Restrictions.Eq(projection, value)));

            case ExpressionType.GreaterThan:
                return(Restrictions.Gt(projection, value));

            case ExpressionType.GreaterThanOrEqual:
                return(Restrictions.Ge(projection, value));

            case ExpressionType.LessThan:
                return(Restrictions.Lt(projection, value));

            case ExpressionType.LessThanOrEqual:
                return(Restrictions.Le(projection, value));

            default:
                throw new NotSupportedException
                      (
                          "the expression contains unsupported features, please revise your code"
                      );
            }
        }
Пример #10
0
        /// <summary>
        ///     Creates a <see cref="ICriterion" /> for the given <see cref="MethodCallExpression" />.
        /// </summary>
        /// <param name="expression">
        ///     The expression.
        /// </param>
        /// <param name="context">
        ///     The helper context.
        /// </param>
        /// <returns>
        ///     The created <see cref="ICriterion" />.
        /// </returns>
        public static ICriterion GetCriterionForMethodCall
        (
            MethodCallExpression expression,
            HelperContext context
        )
        {
            if (IsProjected(expression, context))
            {
                // Not a value expression
                IProjection projection = ProjectionHelper
                                         .GetProjection
                                         (
                    expression.Object ?? expression.Arguments[0],
                    context
                                         );

                int i = expression.Object == null ? 1 : 0;

                switch (expression.Method.Name)
                {
                case "In":
                case "IsIn":

                    object value = ExpressionHelper.GetValue(expression.Arguments[i]);

                    if (!(value is ICollection))
                    {
                        if (value is IEnumerable)
                        {
                            var objs = new List <object>();

                            foreach (object obj in value as IEnumerable)
                            {
                                objs.Add(obj);
                            }

                            return(Restrictions
                                   .In
                                   (
                                       projection,
                                       objs.ToArray()
                                   ));
                        }

                        if (value is IDetachedImmutableFlowQuery)
                        {
                            return(Subqueries
                                   .PropertyIn
                                   (
                                       ExpressionHelper.GetPropertyName(expression, context.RootAlias),
                                       (value as IDetachedImmutableFlowQuery).Criteria
                                   ));
                        }
                    }

                    return(Restrictions
                           .In
                           (
                               projection,
                               value as ICollection
                           ));

                case "Between":
                case "IsBetween":
                    return(Restrictions
                           .Between
                           (
                               projection,
                               ExpressionHelper.GetValue(expression.Arguments[i]),
                               ExpressionHelper.GetValue(expression.Arguments[i + 1])
                           ));

                case "Like":
                case "IsLike":
                    return(GetLikeCriterion(projection, expression.Arguments[i], MatchMode.Exact));

                case "StartsWith":
                    return(GetLikeCriterion(projection, expression.Arguments[i], MatchMode.Start));

                case "EndsWith":
                    return(GetLikeCriterion(projection, expression.Arguments[i], MatchMode.End));

                case "Contains":
                    return(GetLikeCriterion(projection, expression.Arguments[i], MatchMode.Anywhere));

                case "IsLessThan":
                    return(Restrictions.Lt(projection, ExpressionHelper.GetValue(expression.Arguments[i])));

                case "IsLessThanOrEqualTo":
                    return(Restrictions.Le(projection, ExpressionHelper.GetValue(expression.Arguments[i])));

                case "IsGreaterThan":
                    return(Restrictions.Gt(projection, ExpressionHelper.GetValue(expression.Arguments[i])));

                case "IsGreaterThanOrEqualTo":
                    return(Restrictions.Ge(projection, ExpressionHelper.GetValue(expression.Arguments[i])));

                case "IsEqualTo":
                    return(Restrictions.Eq(projection, ExpressionHelper.GetValue(expression.Arguments[i])));

                case "IsNull":
                    return(Restrictions.IsNull(projection));

                case "IsNotNull":
                    return(Restrictions.IsNotNull(projection));
                }

                throw new NotSupportedException
                      (
                          "The expression contains unsupported features, please revise your code"
                      );
            }

            return(Restrictions.Eq(Projections.Constant(ExpressionHelper.GetValue <bool>(expression)), true));
        }