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.

Foi útil?

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 ?

Eu recomendo que você usaria AutoMapper para isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top