2009-07-09 12 views
10

Jak można odwzorować obiekt DataReader na obiekt klasy za pomocą generycznych?C# - Odwzorowanie IDataReader na obiekt przy użyciu generics

Na przykład muszę wykonać następujące czynności:

public class Mapper<T> 
    { 
     public static List<T> MapObject(IDataReader dr) 
     { 
      List<T> objects = new List<T>(); 

      while (dr.Read()) 
      { 
       //Mapping goes here... 
      } 

      return objects; 
     } 
    } 

a później muszę zadzwonić tej klasy metody tak:

IDataReder dataReader = DBUtil.Fetchdata("SELECT * FROM Book"); 

List<Book> bookList = Mapper<Book>.MapObject(dataReder); 

foreach (Book b in bookList) 
{ 
    Console.WriteLine(b.ID + ", " + b.BookName); 
} 

zwrócić uwagę, że Mapper - klasa powinna być możliwość odwzorowania obiektu dowolnego typu reprezentowanego przez T.

+0

Jedna z sugestii - odczytana do IEnumerable z zyskiem zwrotu. –

+0

// mapowanie idzie tutaj, dokładnie to, co pokazałem ci w mojej odpowiedzi, możesz odwzorować dowolny obiekt na czytnik danych (dokładniej: wstrzyknięcie wartości z IDataReader do obiektu DOWOLNY RODZAJ) – Omu

+0

Dlaczego nie używałbyś dedykowane ORM? Wygląda na to, że mikro-ORM jak Dapper jest tutaj odpowiedni. – nawfal

Odpowiedz

3

używam ValueInjecter tego

robię tak:

while (dr.Read()) 
    { 
     var o = new User(); 
     o.InjectFrom<DataReaderInjection>(dr); 
     yield return o; 
    } 

będziesz potrzebować tej ValueInjection to zadziałało:

public class DataReaderInjection : KnownSourceValueInjection<IDataReader> 
    { 
     protected override void Inject(IDataReader source, object target, PropertyDescriptorCollection targetProps) 
     { 
      for (var i = 0; i < source.FieldCount; i++) 
      { 
       var activeTarget = targetProps.GetByName(source.GetName(i), true); 
       if (activeTarget == null) continue; 

       var value = source.GetValue(i); 
       if (value == DBNull.Value) continue; 

       activeTarget.SetValue(target, value); 
      } 
     } 
    } 
+0

Czy jest gdzieś biblioteka powszechnych i użytecznych zastrzyków? –

+0

@PavelHodek nie ma biblioteki, ale jest wiele głównych rozwiązań Valueinjecter w wersji demo, a także na stronach kodeksu – Omu

+0

Kilka rzeczy. 1) Używasz odbicia, aby ustawić wartość, jest to złe dla wydajności. Idź ścieżką ekspresji. 2) Gdzie jest DataReaderInjection i KnownSourceValueInjection w twojej bibliotece? Myślę, że zmieniłeś nazwiska od tej odpowiedzi? 3) Czy korzysta z refleksji za kulisami za każdym razem podczas czytania czytelnika.Zapamiętać, aby uzyskać nazwy właściwości? Mam nadzieję, że nie, ale nie mogę przekonać się, że nie widzę klasy KnownSourceValueInjection. – nawfal

2

Nie wiem, czy pasuje tutaj, ale można użyć słowa kluczowego yield:

public static IEnumerable<T> MapObject(IDataReader dr, Func<IDataReader, T> convertFunction) 
     { 
      while (dr.Read()) 
      { 
       yield return convertFunction(dr); 
      } 
     } 
+0

+1 Interesujące użycie DI. Byłoby miło, gdyby typ T zapewniał również implementację funkcji convertFunction. : D –

+0

To jest ładne DI i można go połączyć z rozwiązaniem Omu. –

1

To będzie bardzo trudne do zrobienia z tego powodu, że są po prostu próbuje map dwie niewiadome razem. W twoim typowym obiekcie typ jest nieznany, aw twoim tablicach danych tabela jest nieznana.

Proponuję więc utworzyć pewien rodzaj atrybutu kolumny, który zostanie dołączony do właściwości twojej istoty. Następnie przejrzyj te atrybuty właściwości i spróbuj wyszukać dane z tych atrybutów w przeglądarce danych.

Twoim największym problemem będzie to, co stanie się, jeśli jedna z właściwości nie zostanie znaleziona w czytniku i odwrotnie, jedna z kolumn w czytniku nie zostanie znaleziona w tym obiekcie.

Powodzenia, ale jeśli chcesz zrobić coś takiego, prawdopodobnie potrzebujesz ORM lub przynajmniej jakiegoś rodzaju implementacji Active Record.

+0

Spójrz na moją odpowiedź, to nie jest takie trudne :) i nie ma wymaganych atrybutów. – Omu

1

Najprostszym sposobem, w jaki mogę myśleć bez celu, jest dostarczenie delegata Func<T,T> do konwersji każdej kolumny i skonstruowania książki.

Ewentualnie, jeśli zastosowałeś się do pewnych konwencji, możesz potencjalnie rozwiązać ten problem za pomocą refleksji. Na przykład, jeśli każda kolumna jest odwzorowana na właściwość w wynikowym obiekcie przy użyciu tej samej nazwy, a użytkownik ograniczył T w programie odwzorowującym do dostarczania możliwego do skonstruowania T, można użyć odbicia, aby ustawić wartość każdej właściwości na wartość w odpowiedniej kolumnie. .

1

co po

abstract class DataMapper 
{ 
    abstract public object Map(IDataReader); 
} 

class BookMapper : DataMapper 
{ 
    override public object Map(IDataReader reader) 
    { 
     ///some mapping stuff 
     return book; 
    } 
} 

public class Mapper<T> 
{ 
    public static List<T> MapObject(IDataReader dr) 
    { 
     List<T> objects = new List<T>(); 
     DataMapper myMapper = getMapperFor(T); 
     while (dr.Read()) 
     { 
      objects.Add((T)myMapper(dr)); 
     } 

     return objects; 
    } 

    private DataMapper getMapperFor(T myType) 
    { 
     //switch case or if or whatever 
     ... 
     if(T is Book) return bookMapper; 

    } 
} 

nie wiem, czy to jest składniowo poprawne, ale mam nadzieję, że u pomysł.

+0

Możesz uniknąć warunków jeśli chcesz i polegać na polimorfizmie pod warunkiem, że klasa Book sama implementuje niektóre funkcje . – nawfal