学海无涯

导航

Dapper 的关系 一对一,一对多,多对多

Dapper 提供了一种称为Multi mapping的功能,使您能够将单行中的数据显式映射到多个对象。

一对多关系

public class Product
{
    public int ProductId { get; set; }
    public string ProductName { get; set; }
    ...
    public Category Category { get; set; }
}

public class Category
{
    public int CategoryId { get; set; }
    public string CategoryName { get; set; }
    ...
    public ICollection<Product> Products { get; set; }
}

 

 

select productid, productname, p.categoryid, categoryname 
from products p 
inner join categories c on p.categoryid = c.categoryid

   执行以上Sql得到以下结果

  

 

[Route("QueryOneToOne")]
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Product>>> QueryOneToOne()
        {//一对一关系查询,一个Product属于一个Category
            var sql = @"select productid,productname,p.categoryid,categoryname from products p
join categories c on p.categoryid=c.categoryid";
            using (var con = new SqlConnection(MyConfig.ConnectionString))
            {//Query和方法有重载,QueryAsync它们采用多个泛型参数和一个Func<TFirst, ..., TReturn> map参数。
                //QueryAsync<Product, Category, Product>,
                //Product, Category,为映射参数,最后一个Product为返回类型
                var products = await con.QueryAsync<Product, Category, Product>
                    (sql, (product, category) =>
                    {//将结果数据映射到返回类型。
                        product.Category = category;
                        product.CategoryId = category.CategoryId;
                        return product;
                    }, splitOn: "CategoryId");
                //splitOn这告诉 Dapper 拆分CategoryId列上的数据。该列之前的任何内容都映射到第一个参数 (Product),
                //该列之后的任何其他内容都应该映射到第二个输入参数 (the Category)。
                return Ok(products);
            }
        }
        [Route("QueryOneToMany")]
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Category>>> QueryOneToMany()
        {//一对多关系查询,一个Category包含多个Product
            var sql = @"select productid,productname,p.categoryid,categoryname from products p
join categories c on p.categoryid=c.categoryid";
            using (var con = new SqlConnection(MyConfig.ConnectionString))
            {//Query和方法有重载,QueryAsync它们采用多个泛型参数和一个Func<TFirst, ..., TReturn> map参数。
                //QueryAsync<Product, Category, Product>,
                //Product, Category,为映射参数,最后一个Product为返回类型
                var categories = await con.QueryAsync<Product, Category, Category>
                    (sql, (product, category) =>
                    {
                        category.Products.Add(product);
                        category.Products.ForEach(m => m.CategoryId = category.CategoryId);
                        return category;
                    }, splitOn: "CategoryId");
                //splitOn这告诉 Dapper 拆分CategoryId列上的数据。该列之前的任何内容都映射到第一个参数 (Product),
                //该列之后的任何其他内容都应该映射到第二个输入参数 (the Category)。
                //用分组去除重复的类别
                var result = categories.GroupBy(c => c.CategoryId).Select(g =>
                {
                    var groupcategory = g.First();
                    groupcategory.Products = g.Select(c => c.Products.Single()).ToList();
                    return groupcategory;
                });
                return Ok(result);
            }
        }

多对多关系

 多重映射也适用于多对多关系。

 

 

public class Tag
{
    public int TagId { get; set; }
    public string TagName { get; set; }
    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Headline { get; set; }
    public string Content { get; set; }
    public Author Author { get; set; }
    public List<Tag> Tags { get; set; } 
}

  

 

 以下 SQL 检索与每个帖子相关的标签信息:

select p.postid, headline, t.tagid, tagname
from posts p 
inner join posttags pt on pt.postid = p.postid
inner join tags t on t.tagid = pt.tagid

每个标签返回一行,导致帖子信息重复:

 

using (var connection = new SQLiteConnection(connString))
{
    var sql = @"select p.postid, headline, t.tagid, tagname
                from posts p 
                inner join posttags pt on pt.postid = p.postid
                inner join tags t on t.tagid = pt.tagid";
    var posts = await connection.QueryAsync<Post, Tag, Post>(sql, (post, tag) => {
        post.Tags.Add(tag);
        return post;
    }, splitOn: "tagid");
//对结果去除重复的记录
    var result = posts.GroupBy(p => p.PostId).Select(g =>
    {
        var groupedPost = g.First();
        groupedPost.Tags = g.Select(p => p.Tags.Single()).ToList();
        return groupedPost;
    });
    foreach(var post in result)
    {
        Console.Write($"{post.Headline}: ");
        foreach(var tag in post.Tags)
        {
            Console.Write($" {tag.TagName} ");
        }
        Console.Write(Environment.NewLine);
    }
}

  

多重关系 

多重映射适用于多重关系。

select p.postid, headline, firstname, lastname, t.tagid, tagname
from posts p 
inner join authors a on p.authorid = a.authorid
inner join posttags pt on pt.postid = p.postid
inner join tags t on t.tagid = pt.tagid

  多重映射函数接受一个额外的输入参数,表示要检索的额外实体:

using (var connection = new SQLiteConnection(connString))
{
    var sql = @"select p.postid, headline, firstname, lastname, t.tagid, tagname
                from posts p 
                inner join authors a on p.authorid = a.authorid
                inner join posttags pt on pt.postid = p.postid
                inner join tags t on t.tagid = pt.tagid";
    var posts = await connection.QueryAsync<Post, Author, Tag, Post>(sql, (post, author, tag) => {
        post.Author = author;
        post.Tags.Add(tag);
        return post;
    }, splitOn: "firstname, tagid");
    var result = posts.GroupBy(p => p.PostId).Select(g =>
    {
        var groupedPost = g.First();
        groupedPost.Tags = g.Select(p => p.Tags.Single()).ToList();
        return groupedPost;
    });
    foreach(var post in result)
    {
        Console.Write($"{post.Headline}: ");
        foreach(var tag in post.Tags)
        {
            Console.Write($" {tag.TagName} ");
        }
        Console.Write($" by {post.Author.FirstName} {post.Author.LastName} {Environment.NewLine}");
    }
}

  

 

  

 

posted on 2022-10-04 16:45  宁静致远.  阅读(631)  评论(0编辑  收藏  举报