C # - IDataReader para mapeamento objeto usando os genéricos
-
12-09-2019 - |
Pergunta
Como posso mapear um objeto DataReader em um objeto de classe usando os genéricos?
Por exemplo eu preciso fazer o seguinte:
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;
}
}
E mais tarde eu preciso chamar esta classe método como o seguinte:
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);
}
Note que, o Mapper - classe deve ser capaz de mapear objeto de qualquer tipo representado por T.
Solução
Eu uso ValueInjecter para este
Estou fazendo assim:
while (dr.Read())
{
var o = new User();
o.InjectFrom<DataReaderInjection>(dr);
yield return o;
}
Você vai precisar deste ValueInjection para que isso funcione:
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);
}
}
}
Outras dicas
Bem, eu não sei se ele se encaixa aqui, mas você poderia estar usando o rendimento palavra-chave
public static IEnumerable<T> MapObject(IDataReader dr, Func<IDataReader, T> convertFunction)
{
while (dr.Read())
{
yield return convertFunction(dr);
}
}
Você pode usar esta classe LateBinder escrevi: http://codecube.net/2008 / 12 / new-latebinder / .
I escreveu outro post com o uso: http://codecube.net/2008 / 12 / utilizando-the-latebinder /
Este vai ser muito difícil de fazer para a razão que você está basicamente tentando mapear duas incógnitas juntos. Em seu objeto genérico do tipo é desconhecido, e em sua datareader a tabela é desconhecido.
Então, o que eu sugiro é que você criar algum tipo de atributo de coluna para anexar as propriedades de você entidade. E depois olhar através desses atributos de propriedade e tentar olhar para cima os dados desses atributos na datareader.
Seu maior problema vai ser, o que acontece se uma das propriedades não é encontrado no leitor, ou vice-versa, uma das colunas do leitor não é encontrado na entidade.
Boa sorte, mas se você quer fazer algo como isso, você provavelmente quer um ORM ou pelo menos algum tipo de implementação do Active Record.
A maneira mais fácil que eu posso pensar de improviso seria fornecer um delegado Func<T,T>
para converter cada coluna e construir o seu livro.
Como alternativa, se você seguiu algumas convenções, você poderia lidar com isso através de reflexão. Por exemplo, se cada coluna mapeada para uma propriedade no objeto resultante usando o mesmo nome, e você restrito T no seu mapeador de proporcionar uma T construível, você poderia usar a reflexão para definir o valor de cada propriedade para o valor na coluna correspondente .
Eu não acho que você vai ser capaz de dar a volta definir a relação entre os campos de alguma forma. Dê uma olhada neste artigo e prestar especial atenção à forma como o mapeamento é definido, ele pode trabalhar para você.
http://www.c-sharpcorner.com/UploadFile /rmcochran/elegant_dal05212006130957PM/elegant_dal.aspx
que sobre seguinte
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;
}
}
Não sei se é sintaticamente correto, mas eu espero u começa a idéia.
Que tal usar Fluente Ado.net ?
Tenha um olhar em http://CapriSoft.CodePlex.com
Eu recomendo que você usaria AutoMapper para isso.