如何从 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"]);
}
我有这个简单的 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"]);
}