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.

10 ответов


Я использую 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);
            }
        }
    }

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

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

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

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


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

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

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

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


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

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


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

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


Как насчет

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;

    }
}

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


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


взгляните на http://CapriSoft.CodePlex.com


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