日期:2014-05-20  浏览次数:20971 次

特别请教@q107770540,关于动态组合条件查询的问题
特别请教@q107770540,以下为完整控制台代码,粘贴后可以直接运行。
按照查询条件,理想的输出产品应为P1、P2、P4,但这里的结果却不对,请问为什么呢?谢谢!

C# code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace LinqTest
{
    // 产品信息
    class Product
    {
        public int CategoryId { get; set; }
        public string Name { get; set; }
        public float Price { get; set; }
    }

    // 产品价格范围条件
    class PriceCondition
    {
        public string Name { get; set; }
        public float Min { get; set; }
        public float Max { get; set; }
    }

    class Program
    {
        static List<Product> _products = new List<Product>();    //产品列表

        static void Main(string[] args)
        {
            //添加产品数据
            _products.Add(new Product() { CategoryId = 1, Name = "P1", Price = 50 });
            _products.Add(new Product() { CategoryId = 2, Name = "P2", Price = 80 });
            _products.Add(new Product() { CategoryId = 3, Name = "P3", Price = 100 });
            _products.Add(new Product() { CategoryId = 2, Name = "P4", Price = 120 });
            _products.Add(new Product() { CategoryId = 4, Name = "P5", Price = 200 });

            //生成价格范围查询条件
            List<PriceCondition> priceRange = new List<PriceCondition>();
            priceRange.Add(new PriceCondition() { Name = "100元以下", Min = 0, Max = 100 });
            priceRange.Add(new PriceCondition() { Name = "150~180元", Min = 150, Max = 180 });

            //查询并输出
            List<Product> result = Search("", new List<int> { 1, 2, 3 }, priceRange);
            foreach(Product pdt in result)
                Console.WriteLine("Name:{0}, CateId:{1}, Price:{2}", pdt.Name, pdt.CategoryId, pdt.Price);
            Console.ReadLine();
        }

        //实现T-SQL效果:    select * from product
        //                where Name like '%keyword%'
        //                and CategoryId in(1,2,3)
        //                and ((price<100) || (price>=150 and price<180))
        static List<Product> Search(string keyword, List<int> cateIds, List<PriceCondition> priceRange)
        {
            Expression<Func<Product, bool>> expression = PredicateExtensions.True<Product>();

            if (!string.IsNullOrEmpty(keyword))
                expression = expression.And(p => p.Name.Contains(keyword));

            if (cateIds != null && cateIds.Count > 0)
                expression = expression.And(p => cateIds.Contains(p.CategoryId));

            if (priceRange != null && priceRange.Count > 0)
            {
                foreach (PriceCondition pc in priceRange)
                {
                    /////////////此处正确写法应该是什么呢?
                    if (pc.Max > 0)
                        expression = expression.Or(p => p.Price >= pc.Min && p.Price < pc.Max);
                    else
                        expression = expression.Or(p => p.Price >= pc.Min);
                }
            }

            return _products.Where(expression.Compile()).ToList();
        }
    }

    static class PredicateExtensions
    {
        public static Expression<Func<T, bool>> True<T>() { return f => true; }

        public static Expression<Func<T, bool>> False<T>() { return f => false; }

        public static Expression<Func<T, bool>> Or<T>(
            this Expression<Func<T, bool>> expression1,
            Expression<Func<T, bool>> expression2
            )
        {
            var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());

            return Expression.Lambda<Func<T, bool>>(Expression.Or(expression1.Body, invokedExpression), expression1.Parameters);
        }

        public static Expression<Func<T, bool>> And<T>(
            this Expression<Func<T, bool>> expression1,
            Expression<Func<T, bool>> expression2
        )
        {
            var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());

            return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters);
        }
    }
}