C # - IDataReader для отображения объектов с использованием обобщений - PullRequest
10 голосов
/ 09 июля 2009

Как я могу отобразить объект 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.

Ответы [ 10 ]

3 голосов
/ 15 июня 2010

Я использую 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);
            }
        }
    }
2 голосов
/ 09 июля 2009

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

public static IEnumerable<T> MapObject(IDataReader dr, Func<IDataReader, T> convertFunction)
        {
            while (dr.Read())
            {
                yield return convertFunction(dr);
            }
        }
1 голос
/ 08 декабря 2010

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

1 голос
/ 08 декабря 2010

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

1 голос
/ 18 августа 2010

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

1 голос
/ 09 июля 2009

как насчет следующих

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;

    }
}

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

1 голос
/ 09 июля 2009

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

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

1 голос
/ 09 июля 2009

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

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

1 голос
/ 09 июля 2009

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

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

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

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

1 голос
/ 09 июля 2009

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

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

...