2

我有一个包含 76 个用户的用户表和用户组表。

使用 MVC、OData、通用存储库和 EF,我尝试在基于用户组进行过滤时优化数据检索:

/api/Users?$filter=USERGROUPS/any(usergroup: usergroup/ID eq 'Group1')

在客户端,我得到了正确数量的用户 - 71(因为 OData 正在根据结果进行过滤),但是我想限制从实际查询返回的记录数 - 即。我不想返回所有记录然后过滤(对于非常大的数据集不是最佳的)。

我的 API 控制器方法如下:

    [Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
    public IQueryable<USER> Get()
    {
        var unitOfWork = new ATMS.Repository.UnitOfWork(_dbContext);

        var users = unitOfWork.Repository<USER>()
                              .Query()
                              .Include(u => u.USERGROUPS)
                              .Get()
                              .OrderBy(order => order.USERNAME);

        unitOfWork.Save();      // includes Dispose()

        return users.AsQueryable();
    }

我在这篇文章中读到:

实体框架负责根据请求构建动态查询。

但是,使用 SQL Server 探查器,执行的查询是请求所有记录,而不是过滤查询。

向查询中添加 .Take() 并不能达到预期的结果,因为我们还需要返回的实际记录数以用于分页目的。

我正在考虑使用通过 ODataQueryOptions 获取一些属性,但这似乎也不太正确。

我对工作单元和存储库的实施是否与我要完成的工作相关,如果是,如何纠正?

4

1 回答 1

0

简单 - 只需设置 Queryable 属性的页面大小 [Queryable(PageSize=10)]

http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options#server-paging

如果您告诉 EF 在哪里应用这些选项,它会起作用。像这样 :

    //[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
    public IQueryable<USER> Get(ODataQueryOptions<USER> options)
    {

        var users = options.ApplyTo(_dbContext.Set<USER>()
                              .Query()
                              .Include(u => u.USERGROUPS)
                              .Get()
                              .OrderBy(order => order.USERNAME));

        return users;
    }

您的代码不起作用,因为它试图将选项应用到最后一行“users.AsQueryable()”,所以实际发生的是 EF 拉取完整数据集,然后将查询应用到最后一行(即作为内存中的集合)。这就是为什么您没有看到没有将“过滤器”传递给 SQL 的原因。

机制是这样的,EF 尝试将 Query 应用于它在代码中找到的 IQueryable 集合(仍然存在一个问题,它如何找到正确的行)。

于 2013-08-07T17:45:41.310 回答