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

     2023-05-07     120

关键词:

【中文标题】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#泛型的使用

01—泛型概述    泛型是用于处理算法、数据结构的一种编程方法。泛型的目标是采用广泛适用和可交互性的形式来表示算法和数据结构,以使它们能够直接用于软件构造。泛型类、结构、接口、委托和方法可以根据它们存... 查看详情

在 C# 中使用泛型的相互依赖的接口

】在C#中使用泛型的相互依赖的接口【英文标题】:InterdependentinterfacesusinggenericsinC#【发布时间】:2011-12-1921:07:08【问题描述】:如果让您感到困惑,我深表歉意。我有这两个主要界面。首先是ISensor接口:publicinterfaceISensor<TRead... 查看详情

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

】关于c#接口和泛型的问题【英文标题】:Aquestionregardingc#interfacesandmaybegenerics【发布时间】:2011-04-2800:01:58【问题描述】:我们已经构建了一个内部工具来生成整个数据访问,每个表都有一个代表它的数据和所有常见操作的类。... 查看详情

泛型的泛型的好处

参考技术A泛型是c#2.0的一个新增加的特性,它为使用c#语言编写面向对象程序增加了极大的效力和灵活性。不会强行对值类型进行装箱和拆箱,或对引用类型进行向下强制类型转换,所以性能得到提高。通过知道使用泛型定义的... 查看详情

c#深入了解泛型

...式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时(instantiate)作为参数指明这些类型。.NETFramework泛型的参数只可以代表类,不能代表个别对象。由于.NETFramework泛型的类型参数之... 查看详情

C#:泛型的语义?

】C#:泛型的语义?【英文标题】:C#:Semanticsforgenerics?【发布时间】:2011-02-0813:59:23【问题描述】:我有一个清单:privatereadonlyIList<IList<GameObjectController>>removeTargets;privatereadonlyIList<IList<GameObjectController>>addT 查看详情

c#中idatareader和dataset的区别是啥呢?

C#中IDataReader和DataSet有什么区别具体怎么使用啊?参考技术A用connection对象和command对象与数据库连接并交互后,有两种方法来访问获取的结果。1.使用DataReader对象,用来逐行从数据源获取数据并处理;2.使用DataSet对象,用来将数据... 查看详情

c#中的泛型

...中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。(也就是说泛型是可以与任何数据类型一起工作的类或方法)模块内高内聚,模块间低耦合。泛型的使用:当我们类/方法不需要关注调用者... 查看详情

泛型的使用

??泛型的使用 *1.在集合中使用泛型(掌握) *2.自己定义泛型类、泛型接口、泛型方法(理解--->使用) *3.泛型与继承的关系 *4.通配符①.在集合中没有使用泛型的情况下 1.没有使用泛型,不论什么Object及其子类... 查看详情

使用 C# 泛型从方法(不是“新”)创建泛型对象

】使用C#泛型从方法(不是“新”)创建泛型对象【英文标题】:UsingC#Genericstocreateagenericobjectfromamethod(not"new")【发布时间】:2012-08-0116:00:01【问题描述】:我习惯了C++模板,并意识到C#中的工作方式略有不同。这就是我想... 查看详情

带有泛型的 C# 不寻常的继承语法

】带有泛型的C#不寻常的继承语法【英文标题】:C#unusualinheritancesyntaxw/generics【发布时间】:2011-06-0515:42:42【问题描述】:我在NHibernate类定义中遇到了这个问题:publicclassSQLiteConfiguration:PersistenceConfiguration<SQLiteConfiguration>所... 查看详情

c#泛型的静态成员(代码片段)

先来看一下代码publicclassStaticDemo<TType>publicstaticintiValue;publicstaticTTypetValue;publicclassTestStaticMonoBehaviour:MonoBehaviourprivatevoidStart()StaticDemo<int>.iValue=1;StaticDemo&l 查看详情

c#泛型的静态成员(代码片段)

先来看一下代码publicclassStaticDemo<TType>publicstaticintiValue;publicstaticTTypetValue;publicclassTestStaticMonoBehaviour:MonoBehaviourprivatevoidStart()StaticDemo<int>.iValue=1;StaticDemo&l 查看详情

c#对泛型实例化对像的方法

最近在搞一个小东东,用到了泛型的处理,用到了对泛型的实例化问题。下面来讲讲对泛型的实例化,以代码为例,如:publicclassA{}publicclassB<T>{  publicstaticTGet(){//在这一块如何实例化T这个对象呢?如果用default(T)这个是不... 查看详情

unity的c#学习——泛型的创建与继承泛型集合类泛型中的约束和反射(代码片段)

...型集合类5、泛型中约束与反射的应用5.1约束——限定可使用的数据类型5.2反射——获取要使用的数据类型泛型C#泛型是C#2.0中引入的一个非常重要的新功能。它允许开发人员编写具有通用行为的类、接口和方法,这些类、接... 查看详情

泛型的小千世界(java)

...定义生成泛型对象3.2泛型对象转成class对象3.3继承关系的使用3.4依赖关系的使用3.5通配符前言  如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^_^。  而且听 查看详情

c#中的泛型

...其的具体参数可延迟到客户代码中声明、实现。这意味着使用泛型的类型参数T,写一个类MyList<T>,客户代码可以这样调用:MyList<int>,MyList<st 查看详情

c#泛型

简介:  先看看泛型的概念--“通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用”。  很多初学者在刚开始接触泛型的时候会比较难理解“泛... 查看详情