С# - 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.
Ответы
Ответ 1
Я использую 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
Ну, я не знаю, подходит ли это здесь, но вы можете использовать ключевое слово yield
public static IEnumerable<T> MapObject(IDataReader dr, Func<IDataReader, T> convertFunction)
{
while (dr.Read())
{
yield return convertFunction(dr);
}
}
Ответ 3
Вы можете использовать этот класс LateBinder, который я написал: http://codecube.net/2008/12/new-latebinder/.
Я написал еще одно сообщение с использованием: http://codecube.net/2008/12/using-the-latebinder/
Ответ 4
Это будет очень сложно сделать по той причине, что вы в основном пытаетесь сопоставить две неизвестные вместе. В вашем общем объекте тип неизвестен, а в вашем datareader таблица неизвестна.
Итак, что бы я предложил, вы создаете какой-то атрибут столбца для присоединения к свойствам вашего объекта. Затем просмотрите эти атрибуты свойств и попытайтесь найти данные из этих атрибутов в datareader.
Ваша самая большая проблема будет, что произойдет, если одно из свойств не будет найдено в читателе, или наоборот, один из столбцов в читателе не будет найден в сущности.
Удачи, но если вы хотите сделать что-то подобное, вы, вероятно, захотите ORM или, по крайней мере, какую-то реализацию Active Record.
Ответ 5
Самый простой способ, с помощью которого я могу думать, - это предоставить делегату Func<T,T>
для преобразования каждого столбца и построения вашей книги.
В качестве альтернативы, если вы следовали некоторым соглашениям, вы могли бы обработать это путем отражения. Например, если каждый столбец сопоставлен с свойством в результирующем объекте с использованием того же имени, и вы ограничили T в своем Mapper на создание конструктивного T, вы можете использовать отражение, чтобы установить значение каждого свойства в значение в соответствующем столбце.
Ответ 6
Я не думаю, что вы сможете обойти определение отношений между полями в какой-то форме. Взгляните на эту статью и обратите особое внимание на то, как определено отображение, оно может сработать для вас.
http://www.c-sharpcorner.com/UploadFile/rmcochran/elegant_dal05212006130957PM/elegant_dal.aspx
Ответ 7
как насчет следующего
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;
}
}
Не знаю, синтаксически ли это правильно, но я надеюсь, что у вас возникнет эта идея.
Ответ 8
Как насчет использования Fluent Ado.net?
Ответ 9
Посмотрите http://CapriSoft.CodePlex.com
Ответ 10
Я бы порекомендовал вам использовать AutoMapper для этого.