3

我有一种方法,我试图返回所有具有匹配性别的默认客户地址。我希望能够通过将 System.Func 方法传递给 where 子句来一点一点地构建过滤查询。

    var emailAddresses = new List<string>();

        // get all customers.
        IQueryable<Customer> customersQ = base.GetAllQueryable(appContext).Where(o => o.Deleted == false);

        // for each customer filter, filter the query.

        var genders = new List<string>() { "C" };

        Func<Customer, bool> customerGender = (o => genders.Contains(o.Addresses.FirstOrDefault(a => a.IsDefaultAddress).Gender));
        customersQ = customersQ.Where(customerGender).AsQueryable();


        emailAddresses = (from c in customersQ
                          select c.Email).Distinct().ToList();

        return emailAddresses;

但是这种方法对每个地址(8000)次调用数据库非常慢。

但是,如果我替换这两行

    Func<Customer, bool> customerGender = (o => genders.Contains(o.Addresses.FirstOrDefault(a => a.IsDefaultAddress).Gender));
        customersQ = customersQ.Where(customerGender).AsQueryable();

用一根线

    customersQ = customersQ.Where(o => genders.Contains(o.Addresses.FirstOrDefault(a => a.IsDefaultAddress).Gender)).AsQueryable();

然后查询只对数据库进行一次调用,速度非常快。

我的问题是为什么这会有所作为?如何使第一种方法只调用一次数据库?

4

1 回答 1

10

使用表达式而不是 Func:

Expression<Func<Customer, bool>> customerGender = (o => 
   genders.Contains(o.Addresses.FirstOrDefault(a => a.IsDefaultAddress).Gender));
customersQ = customersQ.Where(customerGender).AsQueryable();

当您使用简单Func委托时,将调用Where扩展。Enumerable因此,所有数据都进入内存,在内存中对其进行枚举并为每个实体执行 lambda。而且您对数据库有很多调用。

另一方面,当您使用表达式时,会调用Where扩展名Queryable,并将表达式转换为 SQL 查询。这就是为什么您在第二种情况下有单个查询(如果您使用就地 lambda,它将被转换为表达式)。

于 2013-03-05T13:39:50.667 回答