/// <summary>
        /// Constructs an expression that is used to filter entries and execute a search for the specified query
        /// on all string type fields of an entity
        /// </summary>
        /// <param name="searchQuery">The query to be searched for in all string fields</param>
        /// <returns>An expression that can be used in queries to the DB context</returns>
        ///
        /// Example:
        /// For an entity with string properties `Name` and `Address`, the resulting expression
        /// is something like this:
        ///
        /// `x => x.Name.ToLower().Contains(query) || x.Address.ToLower().Contains(query)`
        ///
        internal static Expression <Func <TObject, bool> > ConstructSearchPredicate <TObject>(string searchQuery, params Expression <Func <TObject, string> >[] members)
        {
            // Create constant with query
            var constant = Expression.Constant(searchQuery);

            // Input parameter (e.g. "c => ")
            var parameter = Expression.Parameter(typeof(TObject), "c");

            // Construct expression
            Expression finalExpression = null;

            foreach (var m in members)
            {
                // Visit the provided expression and replace the input parameter with the one defined above ("c")
                // e.g. (from "x.Something" we get "c.Something")
                var memberExpression = new ExpressionParameterVisitor(m.Parameters.First(), parameter)
                                       .VisitAndConvert(m.Body, nameof(ConstructSearchPredicate));

                // Get query expression
                var partialExpression = GetQueryExpression(memberExpression, constant, memberExpression.Type, CompatiblityMode.Strict);

                // Handle case when no OR operation can be constructed
                if (finalExpression == null)
                {
                    finalExpression = partialExpression;
                }
                else
                {
                    finalExpression = Expression.OrElse(finalExpression, partialExpression);
                }
            }

            // Return the constructed expression
            return(Expression.Lambda <Func <TObject, bool> >(finalExpression, parameter));
        }
        /// <summary>
        /// Constructs an expression that is used to filter entries and execute a search for the specified query
        /// on all string type fields of an entity
        /// </summary>
        /// <param name="searchQuery">The query to be searched for in all string fields</param>
        /// <returns>An expression that can be used in queries to the DB context</returns>
        ///
        /// Example:
        /// For an entity with string properties `Name` and `Address`, the resulting expression
        /// is something like this:
        ///
        /// `x => x.Name.ToLower().Contains(query) || x.Address.ToLower().Contains(query)`
        ///
        private static Expression <Func <T, bool> > ConstructSearchPredicate <T>(string searchQuery, params Expression <Func <T, string> >[] fields)
        {
            // Create constant with query
            var constant = Expression.Constant(searchQuery);

            // Input parameter (e.g. "c => ")
            var parameter = Expression.Parameter(typeof(T), "c");

            // Find methods that will be run on each property
            var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            var lowerMethod    = typeof(string).GetMethod("ToLowerInvariant", new Type[0]);

            // Construct expression
            Expression finalBody = null;

            foreach (var f in fields)
            {
                // Visit the provided expression and replace the input parameter with the one defined above ("c")
                // e.g. (from "x.Something" we get "c.Something")
                var propertyExpression = new ExpressionParameterVisitor(f.Parameters.First(), parameter)
                                         .VisitAndConvert(f.Body, nameof(ConstructSearchPredicate));

                // Run lowercase method on property (e.g. "c.<property>.ToLowerInvariant()")
                var transformedProperty = Expression.Call(propertyExpression, lowerMethod);

                // Run contains on property with provided query (e.g. "c.<property>.ToLowerInvariant().Contains(<query>)")
                transformedProperty = Expression.Call(transformedProperty, containsMethod, constant);

                // Handle case when no OR operation can be constructed
                if (finalBody == null)
                {
                    finalBody = transformedProperty;
                }
                else
                {
                    finalBody = Expression.Or(finalBody, transformedProperty);
                }
            }

            // Return the constructed expression
            return(Expression.Lambda <Func <T, bool> >(finalBody, parameter));
        }