如何从 SqlDataReader 填充集合 属性?

How to populate a collection property from SqlDataReader?

我有这个简单的 SQL 查询:

SELECT  CustomerName, OrderId 
FROM    Customer c
        LEFT JOIN Orders o ON o.CustomerId = c.CustomerId

我需要从查询结果中填充我的客户实体:

public class Customer
 {
    public string Name { get; set; }
    public IEnumerable<int> OrderIds { get; set; }
 }

我正在使用 SqlDataReader 读取数据:

using(SqlDataReader rdr = cmd.ExecuteReader())
{      
    while (rdr.Read())
    {
     Customer c = new Customer();
     c.Name = rdr["CustomerName"].ToString();      
     yield return c;
    }
}

问题:在不使用 ORM 的情况下,填写 OrderIds 属性 最简单、最干净的方法是什么?左连接导致查询每个客户 return 多行(因为每个客户都有多个订单)所以现在像上面的代码一样逐行读取它行不通?有什么方法可以填充该实体并仍然使用 yield return 进行延迟执行?

var dataReader = cmd.ExecuteReader();

var dataTable = new DataTable();

dataTable.Load(dataReader);
List<int> orderIds = (from IDataRecord r in rdr
                      where (string) r["CustomerName"] == c.Name
                      select (int)r["OrderIds"]).ToList();

编辑

如果没有 ORM,这有点棘手。然而,另一种选择是使用多个阅读器。这将要求您有两个查询 - 一个针对客户,一个针对订单。例如:

    private void GetCustomerWithOrders()
    {
        using (var conn = new SqlConnection("your connection string"))
        {
            using (var cmd = conn.CreateCommand())
            {
                conn.Open();
                cmd.CommandText = "SELECT CustomerName, CustomerId FROM Customer";
                using (var reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        var customerId = reader.GetInt32(1); // CustomerId
                        List<int> orders = GetOrders(customerId);
                    }
                }
            }
        }
    }

    private List<int> GetOrders(int customerId)
    {
        var orders = new List<int>();
        using (var conn = new SqlConnection("your connectionstring"))
        {
            using (var cmd = new SqlCommand("SELECT OrderId FROM Orders WHERE CustomerId = @CustomerId", conn))
            {
                var param = new SqlParameter
                {
                    ParameterName = "@CustomerId",
                    Value = customerId
                };

                cmd.Parameters.Add(param);
                using (var reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        var orderId = reader.GetInt32(0); // OrderId
                        orders.Add(orderId);
                    }
                }
            }
        }

        return orders;
    }

第一个版本:

var customersRDR = from rCustomers in rdr.Cast<DbDataRecord>()
                   group rCustomers by rCustomers["CustomerName"] into custGroups
                   select new Customer
                   {
                      Name = (string)custGroups.Key,
                      OrderIds = from c in custGroups select (Int32)c["OrderId"]
                   };


第二版:

DataTable dt = new DataTable();
dt.Load(rdr);

var customers = from c in dt.AsEnumerable()
                group c by c["CustomerName"] into custGroups
                select new Customer{
                   Name = custGroups.Key.ToString(),
                   OrderIds = from c in custGroups select Convert.ToInt32(c["OrderId"])
               };


第三版:

DataTable dt = new DataTable();
dt.Load(rdr);

var customerGroups = dt.AsEnumerable()
                     .GroupBy(c => c["CustomerName"]);

foreach (var customer in customerGroups){
     Customer cust = new Customer();
     cust.Name = customerGroup.Key.ToString();
     cust.OrderIds = from c in customerGroup select Convert.ToInt32(c["OrderId"]);
    }