LINQ-To-Entities查询 - 数据库上发生了什么以及本地发生了什么?

时间:2012-06-08 15:33:36

标签: linq-to-entities

在我的WCF服务的业务逻辑中,我有一个允许按一列或多列过滤用户的功能。我进行过滤的方式是这样的:

public List<UserDto> GetUsersByFilters    (
                                              String ssn, 
                                              List<Guid> orderIds, 
                                              List<MaritalStatusEnum> maritalStatuses, 
                                              String name, 
                                              int age
                                          )
{
    using (MyProjEntities entities = new MyProjEntities())
    {
        IQueryable<User> users = entities.Users;

        // Filter By SSN (check if the user's ssn matches)
        if (String.IsNullOrEmusy(ssn) == false)
            users = users.Where(us => us.SSN == ssn);

        // Filter By Orders (check fi the user has all the orders in the list)
        if (orderIds != null)
            users = users.Where(us => UserContainsAllOrders(us, orderIds));

        // Filter By Marital Status (check if the user has a marital status that is in the filter list)
        if (maritalStatuses != null)
            users = users.Where(pt => maritalStatuses.Contains((MaritalStatusEnum)us.MaritalStatus));

        // Filter By Name (check if the user's name matches)
        if (String.IsNullOrEmusy(name) == false)
            users = users.Where(us => us.name == name);

        // Filter By Age (check if the user's age matches)
        if (age > 0)
            users = users.Where(us => us.Age == age);


        return users.ToList();
    }
}

private   Boolean   UserContainsAllOrders(User user, List<Guid> orderIds)
{
    return orderIds.All(orderId => user.Orders.Any(order => order.Id == orderId));
}

我的问题是: 数据库上发生了什么查询以及本地发生了什么?

显然,我不希望每次数据库中的所有用户都被提取到我的记忆中......

我认为因为'按订单过滤'使用本地函数 - 无法在数据库上完成,所以这是在本地完成的。我是对的吗?

如果是这样的话 - 这是否意味着事后发生的一切都会发生在本地?结果呢?

如果“按订单过滤”不存在怎么办?一切都会在数据库方面完成吗?

LINQ-TO-EF是否知道如何将“婚姻状况”查询“转换”为数据库端查询? (我正在检查用户的婚姻状况枚举是否存在于传递给该函数的枚举列表中。)

谢谢!

[编辑:抱歉。我不知道为什么代码没有自动着色]

1 个答案:

答案 0 :(得分:1)

如果你将鼠标悬停在你不同的“where”语句上,你会注意到它们是IQueryable(或者至少它们应该是)......只要你继续追随Iqueryable“where's”到彼此,语句应保持Iqueryable(而不是每次都调用数据库)。

当您最终在底部执行ToList时,就是您实际调用数据库的时候。

当你构建一个linq to ent语句并确保你不会无意中调用一个比你想要的更早返回IEnumerable的扩展时,这一点非常重要。如果你不小心调用了一个返回IEnumerable的扩展,然后开始调用“skip”和“take”,试图进行sql side分页,那么你就错过了......你会跳过并在内存中占用而不是创建优化的SQL查询。

至于到底发生了什么,如果你打开探查器并观察在调用ToList(或任何其他IEnumerable扩展)时提交的sql查询,那将是最有趣的。 Linq to Ent将USUALLY构建一个非常优化的sql语句。例如,添加一个Iqueryable Skip,例如,Linq to Ent将为RowNumber生成必要的sql以及类似的东西,以便它可以有效地进行sql server side paging。 (请注意,随着查询变得越来越复杂,Linq to Ent难以创建最优化的查询。如果复杂的查询开始花费的时间太长,最好捕获正在提交的sql,因为通常可以编写自己更优化的查询查询那些情况)。

您也可以跟踪sql this way