C# - IDataReader 到使用泛型的对象映射

Posted

技术标签:

【中文标题】C# - IDataReader 到使用泛型的对象映射【英文标题】:C# - IDataReader to Object mapping using generics 【发布时间】:2009-07-09 18:00:57 【问题描述】:

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

【问题讨论】:

一个建议 - 读入 IEnumerable 并返回收益。 //映射在这里,正是我在回答中向您展示的内容,您可以将任何对象映射到数据读取器(更准确地说:将值从 IDataReader 注入到任何类型的对象中) 那你为什么不使用专用的 ORM 呢?像 Dapper 这样的微型 ORM 似乎很适合这里。 @nawfal,这是在 2009 年 7 月提出的。 @BROY 老实说,对于 cmets、answers 等,未来的访客也会被考虑在内。而且它不像 2009 年不存在 ORM :) 【参考方案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);
            
        
    

【讨论】:

在某个地方有什么常用和有用的注入库吗? @PavelHodek 没有库,但 valueinjecter 的主要演示解决方案和 codeplex 页面中有很多库 几件事。 1)您正在使用反射来设置值,这对性能不利。走表达路线。 2) DataReaderInjection 和 KnownSourceValueInjection 在您的库中的什么位置?我想你自从这个答案后改名了? 3)是否每次在 while reader.Read 循环中都在幕后使用反射来获取属性名称?我希望没有,但如果没有看到 KnownSourceValueInjection 类,我无法说服自己。 4) 这是次要的但仍然 - 当它在数据库中为 null 时,您没有分配给属性(DBNull 情况),但是如果在 new-ing 中为该属性分配了某个值怎么办构造函数,例如“var o = new User()”?在这种情况下,您返回的用户将与数据库中实际存在的用户不同。【参考方案2】:

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

public static IEnumerable<T> MapObject(IDataReader dr, Func<IDataReader, T> convertFunction)
        
            while (dr.Read())
            
                yield return convertFunction(dr);
            
        

【讨论】:

+1 DI 的有趣用法。最好让 T 类型也提供 convertFunction 的实现。 :D 这是一个不错的 DI,可以和 Omu 的方案结合使用。【参考方案3】:

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

我写了另一篇关于用法的帖子:http://codecube.net/2008/12/using-the-latebinder/

【讨论】:

【参考方案4】:

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

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

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

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

【讨论】:

看我的回答,没那么难:),而且不需要属性【参考方案5】:

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

或者,如果您遵循一些约定,您可以通过反射来处理这个问题。例如,如果每一列使用相同的名称映射到结果对象中的一个属性,并且您在 Mapper 中限制 T 以提供可构造的 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;

    

不知道语法是否正确,但我希望你明白。

【讨论】:

如果 Book 类本身实现了一些 Func,您可以避免 if else 条件并依赖多态性。【参考方案8】:

使用 Fluent Ado.net 怎么样?

【讨论】:

【参考方案9】:

看看http://CapriSoft.CodePlex.com

【讨论】:

【参考方案10】:

我建议您为此使用 AutoMapper。

【讨论】:

以上是关于C# - IDataReader 到使用泛型的对象映射的主要内容,如果未能解决你的问题,请参考以下文章

关于 c# 接口和泛型的问题

泛型的泛型的好处

C# 泛型的使用

C# 泛型

C# 深入了解泛型

unity的C#学习——泛型的创建与继承泛型集合类泛型中的约束和反射