Dapper - 使用单个返回值进行多重映射

7
以下是我用来返回对象分页列表的代码:
string query2 = @"
        select count(*) as TotalCount from blogposts p where p.Deleted = 0 and p.PublishDate <= @date
        select * from (
            select p.*, 
            row_number() over(order by publishdate desc) as rownum
            from blogposts as p
            where p.Deleted = 0 and p.PublishDate <= @date
        ) seq
        where seq.rownum between @x and @y";

using (var cn = new SqlConnection(connectionString))
{
    cn.Open();
    using (var multi = cn.QueryMultiple(query2, new { x= lower, y = upper, date = DateTime.UtcNow }))
    {
        var totalCount = multi.Read<int>().Single();
        var posts = multi.Read<PostModel>().ToList();
        return new PagedList<PostModel>(posts, page, pageSize, x => totalCount);
    }
}

虽然这样可以工作,但这意味着我需要两次定义我的条件,一次用于计数查询,一次用于结果集查询。而不是采用字符串拼接的方式,我可以执行一个查询:
        string query = @"
                select * from (select p.*, 
                row_number() over(order by publishdate desc) as rownum,
                count(*) over() as TotalCount
                from blogposts as p) seq
                where seq.rownum between @x and @y";

然而,我似乎无法使用Dapper进行映射。我不能像上面那样使用相同的方法,因为没有多个结果。我尝试过使用多重映射,但这需要返回IEnumerable。

我该如何映射到以下内容?

    public class PostList
    {
        public IEnumerable<PostModel> Posts;
        public int TotalCount { get; set; }
    }

感谢

1个回答

6

嗯...你不会这样做...

你需要修改你的PostModel,增加一个TotalCount属性...这很丑陋。或者在Select中执行动态重映射,这也很丑陋。

你看,你使用count(*) over()返回了N次计数(*)...这是一种hack方法,使用这种hack方法并不一定更快。在我的某些情况下,我测量到它比运行双查询要慢,特别是在select count(*)中可以缩短一些索引,因为你没有选择所有列。此外,这种hack方法禁用了某些分页优化,例如你不能将select top N添加到查询中。

我的建议是,在分页查询方面要正确地进行索引,这是关键。测量性能并查看这种hack方法是否真的有所帮助(当正确的索引已经放置好了)。

我理解你对字符串连接的担忧,但你总是可以为此定义通用的辅助方法。


谢谢反馈。我想我会坚持使用双查询,然后构建一些辅助工具来保持代码的DRY性。 - Ben Foster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接