如何在Dapper C#中从具有对象列表的对象进行查询

时间:2019-03-14 12:15:11

标签: c# sql dapper

假设我有以下表格:

tb_1: |user_id|user_name|email|age|

tb_2: |item_id|item_name|value|

tb_3: |user_id|item_id|

我有以下模型:

项目:

public class Item {
    public string Name {get; set;}
    public int Value {get; set;}
}

用户:

public class User {
    public Guid UserId {get; set;}
    public List<Item> Itens {get; set;}
}

我正在使用以下查询进行搜索:

using(var connection = ...)
{
    var query1 = "SELECT ... FROM tb_1";
    var query2 = "SELECT ... FROM tb_2 JOIN tb_3 ON ... WHERE tb_3.user_id = @UserId";
    var users = await connection.QueryAsync<User>(query1);
    foreach(var user in users)
    {
        user.Itens = await connection.QueryAsync<Item>(query2, user.UserId);
    }
    return users;
}

是否可以删除foreach并仅使用一个查询?

PS:表格从N到N。

2 个答案:

答案 0 :(得分:0)

我能够解决问题。经过研究,我在Dapper文档中找到了“一对多”查询的解决方案。

string sql = "SELECT TOP 10 * FROM Orders AS A INNER JOIN OrderDetails AS B ON A.OrderID = B.OrderID;";

using (var connection = new SqlCeConnection("Data Source=SqlCe_W3Schools.sdf"))
{           
    var orderDictionary = new Dictionary<int, Order>();


    var list = connection.Query<Order, OrderDetail, Order>(
    sql,
    (order, orderDetail) =>
    {
        Order orderEntry;

        if (!orderDictionary.TryGetValue(order.OrderID, out orderEntry))
        {
        orderEntry = order;
        orderEntry.OrderDetails = new List<OrderDetail>();
        orderDictionary.Add(orderEntry.OrderID, orderEntry);
        }

        orderEntry.OrderDetails.Add(orderDetail);
        return orderEntry;
    },
    splitOn: "OrderID")
    .Distinct()
    .ToList();

    Console.WriteLine(list.Count);

    FiddleHelper.WriteTable(list);
    FiddleHelper.WriteTable(list.First().OrderDetails);
}

参考:Query Multi-Mapping (One to Many)

答案 1 :(得分:-1)

我会说“是,但是:重写查询以使用联接”,即

var query = @"
SELECT ... FROM tb_1

SELECT ... FROM tb_2 JOIN tb_3 ON ... 
INNER JOIN (SELECT UserId FROM tb_1) x -- your original query here
    on tb_3.user_id = x.UserId   -- but as a sub-query
";

然后使用QueryMultiple。这将返回两个 grid ,因此您需要阅读两次-然后在呼叫站点进行分组和分区。

using (var multi = connection.QueryMultiple(sql, ...))
{
    var users = multi.Read<User>().AsList();
    var allItems = multi.Read<Item>().AsList();

    var usersById = users.ToDictionary(x => x.Id);
    foreach(var item in allItems) {
        usersById[item.UserId].Items.Add(item);
    }
    return users;
}