【问题标题】:How do I return one-to-many records in a specific order with Dapper and multi-mapping?如何使用 Dapper 和多重映射以特定顺序返回一对多记录?
【发布时间】:2017-01-31 05:25:36
【问题描述】:

来自Github

Dapper 允许您将单行映射到多个对象。这是一个 如果您想避免无关查询和急切加载,则为关键功能 协会。

例子:

考虑 2 个类:Post 和 User

> class Post {
>     public int Id { get; set; }
>     public string Title { get; set; }
>     public string Content { get; set; }
>     public User Owner { get; set; } }
> 
> class User {
>     public int Id { get; set; }
>     public string Name { get; set; } } 

现在让我们说我们想要映射一个连接两个帖子的查询 和用户表。到现在 如果我们需要合并 2 个查询的结果,我们需要一个新的 反对表达它,但在这种情况下,将 Post 对象内的用户对象。

当我这样做时(我的类名称不同,但构造相同),我得到一个帖子和一个用户,一个帖子和一个用户。我正在使用 Web API,所以这都是 JSON,如果这很重要的话。如果我在 Management Studio 中直接执行 SQL,这就是我看到的方式,你会得到很多行和相应的用户记录

如果我想发回包含用户一次的 JSON 以及数组中的所有帖子,然后是下一个用户、帖子数组等,该怎么办?

id   title    content   id    name
1    Article1 Content1  55  Smith
2    Article2 Content2  55  Smith
3    Article3 Content3  55  Smith

我得到了一遍又一遍地包含用户信息的 JSON(如预期的那样,但不是想要的)。倒退了。

我想要的是一个格式如下的 JSON 对象(我认为这是正确的):

{
  "User": 55,
  "Name": "Smith",
  "Post": [
    {
      "id": 1,
      "title": "title1",
      "content":"MyContent1"
    },
    {
      "id": 2,
      "title": "title2",
      "content":"MyContent2"
    },
    {
      "id": 3,
      "title": "title3",
      "content":"MyContent2"
    }
  ]
}

我该怎么做?现在我得到相反的结果。我以为我会简单地改变课程,但我没有因为 Github 上的说明,“更有意义”的部分。我正在使用这个,

(List<Post>)db.Query<Post, User, Paper>(sqlString, (post, user) => { post.user = user; return post; }, splitOn: "id");

我知道我在这里不需要 splitOn,但在我的实际查询中,名称与 id 不同。

这很接近:

https://www.tritac.com/developers-blog/dapper-net-by-example/

public class Shop {
  public int? Id {get;set;}
  public string Name {get;set;}
  public string Url {get;set;}
  public IList<Account> Accounts {get;set;}
}

public class Account {
  public int? Id {get;set;}
  public string Name {get;set;}
  public string Address {get;set;}
  public string Country {get;set;}
  public int ShopId {get;set;}
}

var lookup = new Dictionary<int, Shop>()
conn.Query<Shop, Account, Shop>(@"
                    SELECT s.*, a.*
                    FROM Shop s
                    INNER JOIN Account a ON s.ShopId = a.ShopId                    
                    ", (s, a) => {
                         Shop shop;
                         if (!lookup.TryGetValue(s.Id, out shop)) {
                             lookup.Add(s.Id, shop = s);
                         }
                         if (shop.Accounts == null) 
                             shop.Accounts = new List<Account>();
                         shop.Accounts.Add(a);
                         return shop;
                     },
                     ).AsQueryable();

var resultList = lookup.Values;

它是第一个对象标识符。不确定我是否可以那样使用它。但这确实像我要求的那样完成了一系列书籍,而且我不必创建一个特殊的对象。本来应该在 Google Code 上的,但是我在 Github 上找不到这个测试。

【问题讨论】:

    标签: dapper multi-mapping


    【解决方案1】:

    由于您的 SQL 查询返回的是平面记录,我建议您创建一个平面 POCO 并使用 dapper 将结果集映射到此集合。在此集合中拥有数据后,您可以使用 LINQ GroupBy 方法按您想要的方式对其进行分组。

    假设你有这样的类

    public class User
    {
      public int Id { set;get;}
      public string Name { set;get;}
      public IEnumerable<Post> Posts { set;get;}
    }
    public class Post
    {
      public int Id { set;get;}
      public string Title{ set;get;}
      public string Content { set;get;}
    }
    

    现在为平面结果集行创建 POCO

    public class UserPost
    {
        public int Id { set; get; }
        public string Title { set; get; }
        public string Content { set; get; }
    
        public int UserId { set; get; }
        public string Name { set; get; }
    }
    

    现在更新您的 SQL 查询以返回列名与上述属性匹配的结果集。

    现在使用 Dapper 获取平面记录

    var userposts= new List<UserPost>();
    using (var conn = new SqlConnection("YourConnectionString"))
    {
        userposts = conn.Query<UserPost>(query).ToList();
    }
    

    现在申请 GroupBy

    var groupedPosts = userposts.GroupBy(f => f.UserId, posts => posts, (k, v) =>
        new User()
        {
            UserId = k,
            Name = v.FirstOrDefault().Name,
            Posts = v.Select(f => new Post() { Id = f.Id, 
                                               Title= f.Title, 
                                               Content = f.Content})
        }).ToList();
    

    【讨论】:

    • 谢谢。我认为多重映射应该阻止我创建其他对象。
    • 您能告诉我您的 GroupBy 使用哪个函数签名吗?我不知道前两个 lambda 是做什么用的。 groupby 在做什么?这个 lambda 中的 f 是什么?
    【解决方案2】:

    另一种选择是使用 .QueryMultiple

        [Test]
        public void TestQueryMultiple()
        {
            const string sql = @"select UserId = 55, Name = 'John Doe'
                        select PostId = 1, Content = 'hello' 
                        union all select PostId = 2, Content = 'world'";
    
            var multi = _sqlConnection.QueryMultiple(sql);
            var user = multi.Read<User>().Single();
            user.Posts = multi.Read<Post>().ToList();
    
            Assert.That(user.Posts.Count, Is.EqualTo(2));
            Assert.That(user.Posts.First().Content, Is.EqualTo("hello"));
            Assert.That(user.Posts.Last().Content, Is.EqualTo("world"));
        }
    

    更新:

    返回多个用户及其帖子:

        [Test]
        public void TestQueryMultiple2()
        {
            const string sql = @"select UserId = 55, Name = 'John Doe'
                        select UserId = 55, PostId = 1, Content = 'hello' 
                        union all select UserId = 55, PostId = 2, Content = 'world'";
    
            var multi = _sqlConnection.QueryMultiple(sql);
            var users = multi.Read<User>().ToList();
            var posts = multi.Read<Post>().ToList();
    
            foreach (var user in users)
            {
                user.Posts.AddRange(posts.Where(x => x.UserId == user.UserId));
            }
    
            Assert.That(users.Count, Is.EqualTo(1));
            Assert.That(users.First().Posts.First().Content, Is.EqualTo("hello"));
            Assert.That(users.First().Posts.Last().Content, Is.EqualTo("world"));
        }
    

    【讨论】:

    • 如果我返回 List 怎么办?我无法将 Single() 返回到 List。
    猜你喜欢
    • 1970-01-01
    • 2018-03-27
    • 1970-01-01
    • 2018-10-03
    • 2011-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多