Example #1
0
        private static Exp CreateSubExpression(Exp pe, Type type, string text, FullTextSearchOptions options, bool isQueriable = false)
        {
            var texts = text.Split(new string[] { "||" }, StringSplitOptions.RemoveEmptyEntries)
                        .Select(t => t.Trim().ToLower())
                        .Where(t => t.Length > 0)
                        .ToList();

            var properties = type.GetProperties().AsEnumerable();

            if (isQueriable)
            {
                properties = properties.GetMappedProperties();
            }

            Exp predicateBody = null;

            foreach (var prop in properties)
            {
                //Check if we can use this property in Search
                if (options == null || options.Filter == null || options.Filter.Invoke(prop))
                {
                    var paramExp = Exp.Property(pe, prop);

                    if (prop.PropertyType == typeof(string) || prop.PropertyType == typeof(int) ||
                        prop.PropertyType == typeof(int?))
                    {
                        Exp notNullExp = null;
                        if (prop.PropertyType == typeof(string))
                        {
                            Exp nullConst = Exp.Constant(null, typeof(string));
                            notNullExp = Exp.NotEqual(paramExp, nullConst);
                        }

                        Exp toStringExp = paramExp;
                        //Check if property has int type
                        if (prop.PropertyType == typeof(int?) || prop.PropertyType == typeof(int))
                        {
                            if (!isQueriable)
                            {
                                Exp toNullableIntExp = null;

                                //property should be nullable
                                if (prop.PropertyType == typeof(int))
                                {
                                    toNullableIntExp = Exp.TypeAs(paramExp, typeof(int?));
                                }

                                Exp valueExp = null;
                                if (toNullableIntExp != null)
                                {
                                    notNullExp = Exp.Property(toNullableIntExp, "HasValue");
                                    valueExp   = Exp.Property(toNullableIntExp, "Value");
                                }
                                else
                                {
                                    notNullExp = Exp.Property(paramExp, "HasValue");
                                    valueExp   = Exp.Property(paramExp, "Value");
                                }

                                notNullExp = Exp.Equal(notNullExp, Exp.Constant(true, typeof(bool)));

                                var convertToString = typeof(Convert).GetMethod("ToString", new[] { typeof(int) });
                                toStringExp = Exp.Call(convertToString, valueExp);
                            }
                            else
                            {
                                var convertToString = typeof(Convert).GetMethod("ToString", new[] { typeof(int) });
                                toStringExp = Exp.Call(convertToString, Exp.Convert(paramExp, typeof(int)));
                            }
                        }

                        Exp peLower = Exp.Call(toStringExp, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));

                        Exp conditionExp = null;
                        foreach (var txt in texts)
                        {
                            var constant    = Exp.Constant(txt, typeof(string));
                            Exp containsExp = Exp.Call(peLower, typeof(string).GetMethod("Contains", new[] { typeof(string) }), constant);
                            if (conditionExp != null)
                            {
                                conditionExp = Exp.OrElse(conditionExp, containsExp);
                            }
                            else
                            {
                                conditionExp = containsExp;
                            }
                        }

                        Exp andExp = (notNullExp != null) ? Exp.AndAlso(notNullExp, conditionExp) : conditionExp;
                        if (predicateBody != null)
                        {
                            predicateBody = Exp.OrElse(predicateBody, andExp);
                        }
                        else
                        {
                            predicateBody = andExp;
                        }
                    }

                    //If this property is't simple and the depth > 0
                    if (options != null && options.Depth != 0 &&
                        !prop.PropertyType.IsSimpleType() && !prop.PropertyType.IsEnumerable())
                    {
                        options.Depth -= 1;
                        var subExp = CreateSubExpression(paramExp, prop.PropertyType, text, options, isQueriable);
                        options.Depth += 1;

                        if (subExp != null)
                        {
                            Exp notNullExp = Exp.NotEqual(paramExp, Exp.Constant(null, typeof(object)));
                            subExp        = Exp.AndAlso(notNullExp, subExp);
                            predicateBody = (predicateBody != null) ? Exp.OrElse(predicateBody, subExp) : subExp;
                        }
                    }
                }
            }

            return(predicateBody);
        }
Example #2
0
        /// <summary>
        /// Filters a sequence of values based on a fulltext search predicate
        /// </summary>
        /// <typeparam name="T">Any type</typeparam>
        /// <param name="source">The source - some IQueryable object.</param>
        /// <param name="text">The text - meaning of the search</param>
        /// <param name="options">The options for full-text search</param>
        /// <returns></returns>
        public static IQueryable <T> FullTextSearchQuery <T>(this IQueryable <T> source, string text, FullTextSearchOptions options = null)
        {
            var pe            = Exp.Parameter(typeof(T), "d");
            var predicateBody = CreateSubExpression(pe, typeof(T), text, options, isQueriable: true);

            if (predicateBody != null)
            {
                var whereExp = Exp.Lambda <Func <T, bool> >(predicateBody, new ParameterExpression[] { pe });
                source = source.Where(whereExp);
            }

            //Order by Expression
            if (options == null)
            {
                return(source);
            }

            var orderByProperty = options.OrderBy;

            if (string.IsNullOrEmpty(orderByProperty))
            {
                orderByProperty = typeof(T).GetProperties().First().Name;
            }

            var property   = Exp.Property(pe, orderByProperty);
            var lambda     = Exp.Lambda(property, pe);
            var method     = options.IsDescendingOrder ? "OrderByDescending" : "OrderBy";
            var orderByExp = Exp.Call(typeof(Queryable), method, new[] { typeof(T), property.Type }, source.Expression, lambda);

            source = source.Provider.CreateQuery <T>(orderByExp) as IOrderedQueryable <T>;
            return(source);
        }