2016-06-29 23 views
1

Ich habe diese einfache SQL-Abfrage:Wie fülle ich eine Auflistungseigenschaft von SqlDataReader?

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

Ich muss meine Customer-Entität aus dem Abfrageergebnis füllen:

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

Ich lese Daten mit SqlDataReader:

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

Frage: Was ist der einfachste und sauberste Weg zum Ausfüllen der OrderIds Eigenschaft ohne Verwendung eines ORM? Der linke Join führt dazu, dass die Abfrage mehrere Zeilen pro Kunde zurückgibt (weil jeder Kunde mehrere Aufträge hat), sodass das Lesen von Zeile für Zeile wie oben beschrieben nicht funktioniert. Gibt es eine Möglichkeit, diese Entität zu füllen und trotzdem die Rendite für eine verzögerte Ausführung zu verwenden?

Antwort

2

1. Version:

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"] 
        }; 


2. Version:

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"]) 
       }; 


3. Version:

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"]); 
    } 
0
var dataReader = cmd.ExecuteReader(); 

var dataTable = new DataTable(); 

dataTable.Load(dataReader); 
+0

W Wenn dies die Frage beantworten könnte, ist es immer gut zu erklären, wie Ihr Code dem OP hilft. –

+0

Das beantwortet die Frage nicht - es umschließt nur die unformatierten Abfrageergebnisse in einem Datentypenobjekt, aber ich möchte die Ergebnisse einer Sammlung meiner "Kunden" -Objekte zuordnen. – BornToCode

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

EDIT

ohne ORM Das ist ein bisschen schwierig zu tun. Eine weitere Option ist die Verwendung mehrerer Leser. Es würde erfordern, dass Sie zwei Abfragen haben - eine für Kunden und eine für Bestellungen. Als Beispiel:

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; 
    } 
+0

Damit werden die Bestellungen des ersten Kunden richtig gelesen, aber dann werden die Zeilen des nächsten Kunden nicht gelesen, weil Sie beim Erreichen aller Zeilen des Lesers ("from IDataRecord r in rdr") tatsächlich das Ende des Datenreader (rdr.Read() == false - keine weiteren Zeilen zum Lesen vorhanden). – BornToCode

+0

@BornToCode Ich habe meine Antwort aktualisiert. Hoffe es hilft dir aus. –