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;
}
}
Не знаю, правильно ли это синтаксически, но я надеюсь, что вы получите эту идею.