dapper 中的多对多多重映射

发布于 2025-01-14 13:49:42 字数 1680 浏览 2 评论 0原文

这是我的数据库

Product
+----+----------+
| Id |   Name   |
+----+----------+
|  1 | Product1 |
|  2 | Product2 |
|  3 | Product3 |
+----+----------+

Category
+----+-----------+
| Id |   Name    |
+----+-----------+
|  1 | Category1 |
|  2 | Category2 |
|  3 | Category3 |
+----+-----------+

ProductCategory
+----+------------+------------+
| Id | ProductId  | CategoryId |
+----+------------+------------+
|  1 |          1 |          1 |
|  2 |          1 |          1 |
|  3 |          2 |          2 |
+----+------------+------------+

现在,我想获取所有产品及其类别。在我的存储库中,我添加了以下代码:

public async Task<IEnumerable<Product>> GetAllProducts()
{
    var products = await _dbConnection.QueryAsync<Product, Category, Product>(
        @"
            SELECT p.Id, p.Name, c.Id, c.Name
            FROM Product p
            LEFT JOIN ProductCategory pc on pc.ProductId = p.Id
            LEFT JOIN Category c on c.Id = pc.CategoryId
        ",
        (product, category) =>
        {
            product.Categories.Add(category);
            return product;
        }, splitOn: "Id",
        transaction: _dbTransaction
    );

    return products.GroupBy(p => p.Id).Select(g =>
    {
        var product = g.First();
        product.Categories = g.Select(p => p.Categories.Single()).ToList();
        return product;
    });
}

在结果中,我得到了 3 个项目的列表:

  • Product1 有 2 个类别(Category1、Category2)
  • Product2 有 1 个类别(Category2)
  • Product3 有 1 个类别(null)

问题是我不想要Product3 使用 null 值填充类别列表。我想要的是在这种情况下有空的类别列表。我应该做什么才能实现这一目标?

This is my database

Product
+----+----------+
| Id |   Name   |
+----+----------+
|  1 | Product1 |
|  2 | Product2 |
|  3 | Product3 |
+----+----------+

Category
+----+-----------+
| Id |   Name    |
+----+-----------+
|  1 | Category1 |
|  2 | Category2 |
|  3 | Category3 |
+----+-----------+

ProductCategory
+----+------------+------------+
| Id | ProductId  | CategoryId |
+----+------------+------------+
|  1 |          1 |          1 |
|  2 |          1 |          1 |
|  3 |          2 |          2 |
+----+------------+------------+

Now, I want to get all products with its categories. In my repository I added this code:

public async Task<IEnumerable<Product>> GetAllProducts()
{
    var products = await _dbConnection.QueryAsync<Product, Category, Product>(
        @"
            SELECT p.Id, p.Name, c.Id, c.Name
            FROM Product p
            LEFT JOIN ProductCategory pc on pc.ProductId = p.Id
            LEFT JOIN Category c on c.Id = pc.CategoryId
        ",
        (product, category) =>
        {
            product.Categories.Add(category);
            return product;
        }, splitOn: "Id",
        transaction: _dbTransaction
    );

    return products.GroupBy(p => p.Id).Select(g =>
    {
        var product = g.First();
        product.Categories = g.Select(p => p.Categories.Single()).ToList();
        return product;
    });
}

In results, I got list of 3 items:

  • Product1 with 2 categories (Category1, Category2)
  • Product2 with 1 category (Category2)
  • Product3 with 1 category (null)

The problem is that I don't want Product3 to have filled category list with null value. What I wanted is to have empty Category list in this case. What should I do to achieve that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

银河中√捞星星 2025-01-21 13:49:42

为什么不直接将映射函数更改为?:

(product, category) =>
{
    if (category!=null)
    {
        product.Categories.Add(category);
    }
    return product;
}

对于 GroupBy 中的 .Single() 来说,这当然会失败,但是无论如何,您将如何按缺失的类别进行分组呢?

Why not just change the mapping function to?:

(product, category) =>
{
    if (category!=null)
    {
        product.Categories.Add(category);
    }
    return product;
}

That will of course fail for the .Single() in GroupBy, but how would you group by missing category anyway?

你的笑 2025-01-21 13:49:42

首先从查询中返回原始数据,然后进行一些处理会更容易。然后你就可以将所有逻辑集中在一处。例如:

var products = await _dbConnection
    .QueryAsync<Product, Category, (Product Product, Category Category)>(
    @"
        SELECT p.Id, p.Name, c.Id, c.Name
        FROM Product p
        LEFT JOIN ProductCategory pc on pc.ProductId = p.Id
        LEFT JOIN Category c on c.Id = pc.CategoryId
    "
    ,(product, category) => (product, category)
    , splitOn: "Id"
    ,transaction: _dbTransaction
);

return products.GroupBy(pc => pc.Product.Id)
    .Select(g =>
    {
        var product = g.First().Product;
        product.Categories = g.Select(pc => pc.Category)
            .Where(c => c != null).ToList();
        return product;
    });

null 检查会跳过由于外连接而不可避免地出现在 SQL 结果集中的 null 类别。

It's easier to return the raw data from the query first and then do some processing. Then you have all logic in one place. For example:

var products = await _dbConnection
    .QueryAsync<Product, Category, (Product Product, Category Category)>(
    @"
        SELECT p.Id, p.Name, c.Id, c.Name
        FROM Product p
        LEFT JOIN ProductCategory pc on pc.ProductId = p.Id
        LEFT JOIN Category c on c.Id = pc.CategoryId
    "
    ,(product, category) => (product, category)
    , splitOn: "Id"
    ,transaction: _dbTransaction
);

return products.GroupBy(pc => pc.Product.Id)
    .Select(g =>
    {
        var product = g.First().Product;
        product.Categories = g.Select(pc => pc.Category)
            .Where(c => c != null).ToList();
        return product;
    });

The null check skips the null category that's inevitably in the SQL result set because of the outer joins.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文