System.Func传入一个没有枚举的方法的linq

Tim*_*kin 3 c# linq lambda

我有一种方法,我试图返回具有匹配性别的所有默认客户地址.我希望能够通过在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;
Run Code Online (Sandbox Code Playgroud)

但是这个方法为每个地址(8000)调用数据库,这非常慢.

但是,如果我更换两条线

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

有一条线

    customersQ = customersQ.Where(o => genders.Contains(o.Addresses.FirstOrDefault(a => a.IsDefaultAddress).Gender)).AsQueryable();
Run Code Online (Sandbox Code Playgroud)

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

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

Ser*_*kiy 10

使用表达式而不是Func:

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

当您使用简单Func委托时,则调用Where扩展名Enumerable.因此,所有数据都进入内存,枚举它并为每个实体执行lambda.你有很多数据库调用.

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