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我为此使用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<T,T>
代表来转换每一列并构建你的书。
或者,如果您遵循一些约定,您可以通过反射来处理这个问题。例如,如果每一列使用相同的名称映射到结果对象中的一个属性,并且您在 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使用 Fluent Ado.net 怎么样?
【讨论】:
【参考方案9】:看看http://CapriSoft.CodePlex.com
【讨论】:
【参考方案10】:我建议您为此使用 AutoMapper。
【讨论】:
以上是关于C# - IDataReader 到使用泛型的对象映射的主要内容,如果未能解决你的问题,请参考以下文章