C # - IDataReader для отображения объектов с использованием обобщений

Как я могу сопоставить объект DataReader в объект класса с помощью обобщений?

Например мне нужно сделать следующее:

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

И позже мне нужно вызвать этот метод класса следующим образом:

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

Обратите внимание, что класс Mapper должен иметь возможность отображать объекты любого типа, представленного T.

 nawfal29 июл. 2015 г., 22:27
Почему бы тогда не использовать выделенный ORM? Микро-ORM, такой как Dapper, кажется, здесь хорошо подходит.
 Omu15 июн. 2010 г., 13:40
// здесь идет сопоставление, именно то, что я показал вам в своем ответе, вы можете отобразить любой объект в считыватель данных (точнее: ввести значения из IDataReader в объект ЛЮБОГО ТИПА)
 user36631229 июл. 2015 г., 22:28
@nawfal, об этом спросили в июле 2009 года.
 Daniel A. White09 июл. 2009 г., 20:02
Одно предложение - читать в IEnumerable & lt; T & gt; с возвратом дохода.
 nawfal29 июл. 2015 г., 22:35
@ BROY Честно говоря, с комментариями, ответами и т. Д. Всегда учитываются и будущие посетители. И это не похоже на то, что ORM не существовало в 2009 году :)

Ответы на вопрос(10)

Я бы порекомендовал вам использоватьAutoMapper за это.

Это будет очень трудно сделать по той причине, что вы в основном пытаетесь сопоставить два неизвестных вместе. В вашем универсальном объекте тип неизвестен, а в вашем хранилище данных таблица неизвестна.

Поэтому я хотел бы предложить вам создать некоторый атрибут столбца для привязки к свойствам вашей сущности. Затем просмотрите эти атрибуты свойств и попробуйте найти данные из этих атрибутов в устройстве чтения данных.

Ваша самая большая проблема будет состоять в том, что произойдет, если одно из свойств не будет найдено в читателе, или наоборот, один из столбцов в читателе не найден в объекте.

Удачи, но если вы хотите сделать что-то подобное, вам, вероятно, понадобится ORM или, по крайней мере, какая-то реализация Active Record.

 18 авг. 2010 г., 08:17
посмотрите на мой ответ, это не так сложно :) и никаких атрибутов не требуется

Как насчет использования Свободный Ado.net?

Вы можете использовать этот класс LateBinder, который я написал:http://codecube.net/2008/12/new-latebinder/.

Я написал еще один пост с использованием:http://codecube.net/2008/12/using-the-latebinder/

Посмотри наhttp://CapriSoft.CodePlex.com

Решение Вопроса

я используюValueInjecter за это

Я делаю так:

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

вам понадобится этот ValueInjection для этого:

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);
            }
        }
    }
 14 дек. 2012 г., 16:38
@PavelHodek - это не библиотека, но их много в основном демонстрационном решении valueinjecter, а также на страницах codeplex.
 14 дек. 2012 г., 15:44
Есть ли где-нибудь библиотека общих и полезных уколов?
 29 июл. 2015 г., 16:55
Мало вещей. 1) Вы используете отражение для установки значения, это ухудшает производительность. Пройдите экспресс-маршрут. 2) Где в вашей библиотеке находятся DataReaderInjection и KnownSourceValueInjection? Я думаю, что вы изменили имена с тех пор, как этот ответ? 3) Использует ли он отражение за кулисами каждый раз в цикле while reader.Read, чтобы получить имена свойств? Я надеюсь, что нет, но не могу убедить себя, не видя класс KnownSourceValueInjection.
 29 июл. 2015 г., 17:10
4) Это незначительно, но все же - вы не присваиваете свойству свойство, когда оно равно нулю в базе данных (случай DBNull), но что, если этому свойству присваивается какое-то значение при обновлении в конструкторе, например & quot; var o = новый пользователь () & quot ;? В этом случае возвращаемый вами пользователь будет отличаться от того, что фактически присутствует в БД.

Самым простым способом, который я могу придумать, было бы поставитьFunc<T,T> делегат для преобразования каждого столбца и построения вашей книги.

В качестве альтернативы, если вы следовали некоторым соглашениям, вы могли бы справиться с этим с помощью рефлексии. Например, если каждый столбец сопоставлен со свойством в результирующем объекте с тем же именем, и вы ограничили T в своем Mapper предоставлением конструируемого T, вы можете использовать отражение, чтобы установить значение каждого свойства равным значению в соответствующем столбце. ,

как насчет следующего

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;

    }
}

Не знаю, правильно ли это синтаксически, но я надеюсь, что вы поняли идею.

 29 июл. 2015 г., 17:01
Вы можете избежать условий if else и полагаться на полиморфизм, если сам класс Book реализует некоторые функции & lt; IDataRecord, Book & gt ;.

Я не думаю, что вы сможете обойти определение отношений между полями в той или иной форме. Посмотрите на эту статью и обратите особое внимание на то, как определяется отображение, оно может работать на вас.

http://www.c-sharpcorner.com/UploadFile/rmcochran/elegant_dal05212006130957PM/elegant_dal.aspx

Ну, я не знаю, подходит ли он здесь, но вы могли бы использовать ключевое слово yield

public static IEnumerable<T> MapObject(IDataReader dr, Func<IDataReader, T> convertFunction)
        {
            while (dr.Read())
            {
                yield return convertFunction(dr);
            }
        }
 14 дек. 2012 г., 15:39
Это хороший DI, и его можно комбинировать с решением Omu.
 09 июл. 2009 г., 20:08
+1 Интересное использование DI. Было бы неплохо, чтобы тип T также обеспечивал реализацию convertFunction. : D

Ваш ответ на вопрос