10

如何使用泛型将 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 表示的任何类型的对象。

4

10 回答 10

3

我为此使用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);
            }
        }
    }
于 2010-06-15T09:00:24.757 回答
2

好吧,我不知道它是否适合这里,但你可以使用 yield 关键字

public static IEnumerable<T> MapObject(IDataReader dr, Func<IDataReader, T> convertFunction)
        {
            while (dr.Read())
            {
                yield return convertFunction(dr);
            }
        }
于 2009-07-09T18:04:35.683 回答
1

你可以使用我写的这个 LateBinder 类:http: //codecube.net/2008/12/new-latebinder/

我用用法写了另一篇文章:http: //codecube.net/2008/12/using-the-latebinder/

于 2009-07-09T18:06:25.287 回答
1

这将很难做到,因为您基本上是在尝试将两个未知数映射在一起。在您的通用对象中,类型是未知的,而在您的数据阅读器中,表是未知的。

所以我建议您创建某种列属性以附加到您的实体的属性。然后查看这些属性属性并尝试从数据读取器中的这些属性中查找数据。

您最大的问题是,如果在阅读器中找不到属性之一,或者在实体中找不到阅读器中的列之一,会发生什么情况。

祝你好运,但如果你想做这样的事情,你可能需要一个 ORM 或至少某种 Active Record 实现。

于 2009-07-09T18:06:40.420 回答
1

我能想到的最简单的方法是提供一个Func<T,T>代表来转换每一列并构建你的书。

或者,如果您遵循一些约定,您可以通过反射来处理这个问题。例如,如果每一列使用相同的名称映射到结果对象中的一个属性,并且您在 Mapper 中限制 T 以提供可构造的 T,则可以使用反射将每个属性的值设置为相应列中的值.

于 2009-07-09T18:07:03.897 回答
1

我认为您无法绕过以某种形式定义字段之间的关系。看看这篇文章,并特别注意映射是如何定义的,它可能对你有用。

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

于 2009-07-09T18:14:30.497 回答
1

跟随呢

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;

    }
}

不知道它在语法上是否正确,但我希望你明白这一点。

于 2009-07-09T18:29:03.650 回答
1

使用Fluent Ado.net 怎么样?

于 2010-08-18T06:42:09.757 回答
1

看看http://CapriSoft.CodePlex.com

于 2010-12-08T08:54:06.923 回答
1

我建议您为此使用AutoMapper

于 2010-12-08T09:06:48.077 回答