2012-06-30 11 views
9

Obecnie używam coś takiego:Jak mogę odwzorować wyniki zapytania sql na obiekty?

try 
    { 
     dr = SQL.Execute(sql); 

     if(dr != null) { 
     while(dr.Read()) { 
      CustomObject c = new CustomObject(); 
      c.Key = dr[0].ToString(); 
      c.Value = dr[1].ToString(); 
      c.Meta = dr[2].ToString(); 
      customerInfo.CustomerList.Add(c); 
     } 
     } 
     else 
     { 
      customerInfo.ErrorDetails="No records found"; 
     } 

zamiast mnie robi assigments ręcznie, czy istnieje sposób, aby zrobić to bezpośrednio mapowanie (zakładamy, że nazwy kolumn pasuje z nazwami pól).

Jednym z wymagań jest jednak to, że chcę to zrobić przez moje obecne podejście do używania kwerend SQL, a nie przez stosowanie czystych metod opartych na LINQ. Po pierwsze, zapytania SQL są wystarczająco duże, wymagają złożonych JOINów i zostały dokładnie przetestowane, więc nie chcę wprowadzać więcej błędów w tej chwili. Jakieś sugestie?

+2

Należy pamiętać, że * można * używać LINQ z niestandardowymi zapytaniami SQL, a to automatycznie zamapuje pola w wyniku zapytania na ogólny typ obiektu, który podasz. Zobacz [** 'DataContext.ExecuteQuery' **] (http://msdn.microsoft.com/en-us/library/bb361109.aspx) – mellamokb

+0

@mellamokb: Czy możesz pokazać mi jak? Lub przynajmniej wskaż mi jakiś zasób, a może to, czego powinienem szukać? – Legend

+0

Zobacz link, który dodałem, czyli konkretną metodę, której potrzebujesz. Istnieją również przykłady na tej stronie. – mellamokb

Odpowiedz

4

Jednym prostym rozwiązaniem byłoby stworzenie konstruktora dla Twojego CustomObject, który zajmuje DataRow (na przykładzie, więc jeśli jest to kolejna klasa, popraw mnie).

W swoim nowym konstruktorze rób to, co robisz we własnym przykładzie.

public CustomObject(DataRow row) 
{ 
    Key = row[0].ToString(); 
    // And so on... 
} 

Innym sposobem byłoby wprowadzenie leków generycznych i zrobić nową funkcję w swojej SQL klasy

Przykład (Took kod z Passing arguments to C# generic new() of templated type):

// This function should reside in your SQL-class. 
public IEnumerable<T> ExecuteObject<T>(string sql) 
{ 
    List<T> items = new List<T>(); 
    var data = ExecuteDataTable(sql); // You probably need to build a ExecuteDataTable for your SQL-class. 
    foreach(var row in data.Rows) 
    { 
     T item = (T)Activator.CreateInstance(typeof(T), row); 
     items.Add(item); 
    } 
    return items; 
} 

Przykład użycia:

public IEnumerable<CustomObject> GetCustomObjects() 
{ 
    return SQL.ExecuteObject<CustomObject>("SELECT * FROM CustomObject"); 
} 

Testowałem ten kod w LinqPadzie, powinno działać.

3

Możesz to osiągnąć, tworząc ogólną metodę dla swoich wymagań. Możesz również ustawić nową metodę jako rozszerzenie tabeli danych.

public static List<T> ToList<T>(this DataTable table) where T : class, new() 
{ 
    try 
    { 
     List<T> list = new List<T>(); 

     foreach (var row in table.AsEnumerable()) 
     { 
      T obj = new T(); 

      foreach (var prop in obj.GetType().GetProperties()) 
      { 
       try 
       { 
        PropertyInfo propertyInfo = obj.GetType().GetProperty(prop.Name); 
        propertyInfo.SetValue(obj, Convert.ChangeType(row[prop.Name], propertyInfo.PropertyType), null); 
       } 
       catch 
       { 
        continue; 
       } 
      } 

      list.Add(obj); 
     } 

     return list; 
    } 
    catch 
    { 
     return null; 
    } 
} 

}

Zastosowanie:

DataTable dtCustomer = GetCustomers(); 
    List<CustomObject> CustomObjectList = dtCustomer.ToList<CustomObject>(); 
2

Należy zajrzeć do MicroORMs. W przeciwieństwie do zwykłych ORM, które zapewniają SDL, której musisz użyć, MicroORMs pozwalają ci używać własnych zapytań SQL i dostarczają mapowanie z zestawów wyników SQL do obiektów C# i obiektów C# do parametrów SQL.

Moim ulubionym jest PetaPoco, który zapewnia również program budujący zapytania, który używa własnego kodu SQL, ale wykonuje kilka porządnych operacji na numerach parametrów.

0

Następująca funkcja przyjmuje ciąg SQL i obiekt, wymaga, aby obiekt posiadał właściwość dla każdej kolumny w instrukcji select. Obiekt musi być utworzony.

obiekt publiczny SqlToSingleObject (string sSQL, obiekt o) {

 MySql.Data.MySqlClient.MySqlDataReader oRead; 
     using (ConnectionHelper oDb = new ConnectionHelper()) 
     { 
      oRead = oDb.Execute(sSql); 
      if (oRead.Read()) 
      { 

       for (int i = 0; i < oRead.FieldCount; i++) 
       { 

        System.Reflection.PropertyInfo propertyInfo = o.GetType().GetProperty(oRead.GetName(i)); 
        propertyInfo.SetValue(o, Convert.ChangeType(oRead[i], propertyInfo.PropertyType), null); 
       } 
       return o; 
      } 
      else 
      { 
       return null; 

      } 

     } 

    } 
+0

Co to za cel? Jeśli masz zamiar stworzyć wszystkie zalety, może po prostu sam zbuduj obiekt. – MattE

1

Założenie: jeśli potrzebujesz tylko dla serializacji obiektów lub prostego wyjścia ad-hoc.

Można użyć ExpandoObject i SqlDataReader.GetSchemaTable() tak:

private IEnumerable<dynamic> ReaderToAnonymmous(SqlCommand comm) { 
     using (var reader = comm.ExecuteReader()) { 
      var schemaTable = reader.GetSchemaTable(); 

      List<string> colnames = new List<string>(); 
      foreach (DataRow row in schemaTable.Rows) { 
       colnames.Add(row["ColumnName"].ToString()); 
      } 

      while (reader.Read()) { 
       var data = new ExpandoObject() as IDictionary<string, Object>; 
       foreach (string colname in colnames) { 
        var val = reader[colname]; 
        data.Add(colname, Convert.IsDBNull(val) ? null : val); 
       } 

       yield return (ExpandoObject)data; 
      } 
     } 
    } 

Chociaż nie są księgowane szybszych rozwiązań (i pisał to jako alternatywny leniwe podejście do ad-hoc wyników SQL/czytelników/wyjścia).

+0

To jest niesamowite, dokładnie to, czego szukałem. Jestem konsolową aplikacją, która generuje raporty w Excelu z procedur przechowywanych, a dzięki temu kawałkowi kodu nie muszę mapować procedur w obrębie aplikacji. Dziękuję Ci. – v1n1akabozo

Powiązane problemy