我有一个包含76个用户和UserGroups表的Users表。
使用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();
}
我在this post中读到:
实体框架负责构建基于的动态查询 请求。
但是,使用SQL Server探查器时,执行的查询是请求所有记录,而不是筛选的查询。
在查询中添加.Take()无法实现所需的结果,因为我们还需要为分页目的返回的实际记录数。
我正在考虑通过ODataQueryOptions使用抓取一些属性,但这似乎也不正确。
我的工作单元和存储库的实现是否与我想要完成的内容不一致,如果是,那么如何纠正?
答案 0 :(得分:0)
简单 - 只需为Queryable atrribute设置页面大小[可查询(PageSize = 10)]
如果您告诉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拉出FULL数据集,然后将查询应用到最后一行line(在内存集合中)。这就是为什么你没有看到“过滤器”没有被传递给SQL。
机制就是这样,EF尝试将Query应用到它在代码中找到的IQueryable集合(还有一个问题是如何找到正确的行)。