预先感谢您花时间阅读此问题。
我的数据库中有一个视图,我们称之为 Members_VW
在我的 .net 5 API 中,我尝试使用搜索参数从视图中获取成员列表的分页响应。我还需要返回前端的响应总数,以了解结果将在多少页中返回。
目前 Members_VW 是通过如下查询创建的:
select
col1, col2, col3
from
table1 1
inner join table2 2 on 1.key = 2.key
inner join tble3 3 on 3.key = 2.key
where
defaultcondition1 = '1'
and
defaultcondition2 = '2'
我提到了this答案并尝试使用CTE,最终将我的视图更改为使用这样的查询:
with cte1 as (
select
col1, col2, col3
from
table1 1
inner join table2 2 on 1.key = 2.key
inner join tble3 3 on 3.key = 2.key
where
defaultcondition1 = '1'
and
defaultcondition2 = '2')
cte2 as (
select count(*) over() from cte1 )
select
*
from
cte1, cte2
但这不起作用,因为它总是返回
cte1
中的总行数,而不应用任何过滤器。
于是,我继续尝试构造查询以返回应用条件后的总行数,发现这个查询有效:
select
col1, col2, col3, count(*) over()
from
table1 1
inner join table2 2 on 1.key = 2.key
inner join tble3 3 on 3.key = 2.key
where
defaultcondition1 = '1'
and
defaultcondition2 = '2'
目前,我正在尝试使用 EF Core 实现相同的查询,但很难实现。
我已经尝试实现here提供的解决方案,但正如其中一条评论所暗示的那样,这种实现不再被允许。
我试图避免使用原始查询的实现。有没有办法在不使用原始查询的情况下从
count(*) over()
获取结果?
以下是我当前的实现:
IQueryable<MembersVW> membersQuery = _context.MembersVW;
membersQuery = membersQuery.Where(u => u.MemberId == memberid);
membersQuery = membersQuery.OrderBy(m => m.MemberId).Skip(page * size).Take(size);
当我这样做时:
membersQuery = membersQuery.Count()
我返回时出现以下错误:
Error CS0029 Cannot implicitly convert type 'int' to 'System.Linq.IQueryable<PersonalPolicyAPI.Models.VwPersonalPolicyMember>'
再次感谢您阅读我的问题,感谢您提供的任何帮助。 🙏🏾
我已阅读您关于是否可以通过一个查询完成的问题。虽然我不知道有什么方法可以使用 1 个查询来完成此操作,但我可以提供另一种解决方案,该解决方案将帮助您解决对性能和 2 个查询的担忧。我经常这样做。 😁 尝试:
//execute both queries at the same time instead of sequentially
//assuming _context exists and you know how to new up a new instance
var ctxt2 = new MembersContext();
var countqry = _context.Members.CountAsync();
var pageqry = ctxt2.Members.OrderBy(m=>m.MemberId).Skip(page*size).Take(size).ToListArray();
//wait for them both to complete
Task.WaitAll(countqry, pageqry);
//use the results
var count = countqry.Result;
var page = pageqry.Result;
您尝试将计数值(整数)分配给查询变量(IQueryable)。这就是全部内容了。
如果您想在单个查询中执行此操作,正如您在评论中建议的那样,您可以首先执行查询以获取所有条目,然后对结果进行计数,然后使用skip/take 过滤结果。这很可能不是最有效的方法,但它应该有效。
如果您不修改此函数/api 中的任何数据,我还建议使用 AsNoTracking()。
编辑: 我现在建议这个解决方案。计数速度很快,因为它实际上不获取任何数据,只是计算行数。不过,这仍然是两个问题,我会尝试将其合并并稍后编辑我的答案。
var count = await yourContext.YourTable.CountAsync();
var data = await yourContext.YourTable
.OrderBy(x => x.YourProp)
.Skip(10).Take(10)
//.AsNoTracking()
.ToListAsync();
编辑2: 好吧,所以,我还不能让它只在 DB-Call 上进行,但是,我可以在语法上将它组合起来。然而,我第一次编辑的方法更容易阅读并且基本相同。尽管如此,要更深入地研究这个问题,必须有一种时髦的方法来做到这一点。
var query = yourContext.YourTable.AsQueryable();
var result = await query.OrderBy(x => x.Prop)
.Select(x => new {Data = x, Count = query.Count()} )
.Skip(50).Take(50)
.AsNoTracking()
.ToListAsync();
var count = result.FirstOrDefault()?.Count ?? 0; //If empty/null return 0
var data = result.Select(x => x.Data).ToList();
在
membersQuery = membersQuery.Count()
行中,您将整数值分配给可查询列表,这是不正确的。您可以在查询后获取列表项计数,如下所示
membersQuery = membersQuery.OrderBy(m => m.MemberId).Skip(page * size).Take(size);
int totalCount = membersQuery.Count();
要在同一列表中获取计数列,您首先需要在 MembersVW 类中添加 Count 属性,然后使用 LINQ 投影添加列值。
解决方案-1:
memberQuery = membersQuery.Select(p => new MembersVW
{
col1 = p.col1
col2 = p.col2
col3 = p.col3
count = totalCount
});
解决方案2:
使用 LINQ foreach 循环,即
membersQuery.ForEach(item =>
{
item.count = totalCount;
});
membersQuery.Count() 返回整数而不是可查询的
你可以做
int count = membersQuery.Count();
List<MemberVW> = membersQuery.OrderBy(m => m.MemberId).Skip(page * size).Take(size).ToList();
你可以用
返回 public class MemberVwWithCount {
public int Count{get;set;}
public List<MemberVW> Members {get; set;}
}