C# 使用Reflection和IDataReader.GetSchemaTable创建读取和处理IDataReader';s当前结果集
我正在编写一个类,它封装了使用ADO.NET从数据库检索数据的复杂性。其核心方法是C# 使用Reflection和IDataReader.GetSchemaTable创建读取和处理IDataReader';s当前结果集,c#,ado.net,C#,Ado.net,我正在编写一个类,它封装了使用ADO.NET从数据库检索数据的复杂性。其核心方法是 private void Read<T>(Action<T> action) where T : class, new() { var matches = new LinkedList<KeyValuePair<int, PropertyInfo>>(); // Read the current result set's metadata.
private void Read<T>(Action<T> action) where T : class, new() {
var matches = new LinkedList<KeyValuePair<int, PropertyInfo>>();
// Read the current result set's metadata.
using (DataTable schema = this.reader.GetSchemaTable()) {
DataRowCollection fields = schema.Rows;
// Retrieve the target type's properties.
// This is functionally equivalent to typeof(T).GetProperties(), but
// previously retrieved PropertyInfo[]s are memoized for efficiency.
var properties = ReflectionHelper.GetProperties(typeof(T));
// Attempt to match the target type's columns...
foreach (PropertyInfo property in properties) {
string name = property.Name;
Type type = property.PropertyType;
// ... with the current result set's fields...
foreach (DataRow field in fields) {
// ... according to their names and types.
if ((string)field["ColumnName"] == name && field["DataType"] == type) {
// Store all successful matches in memory.
matches.AddLast(new KeyValuePair<int, PropertyInfo>((int)field["ColumnOrdinal"], property));
fields.Remove(field);
break;
}
}
}
}
// For each row, create an instance of the target type and set its
// properties to the row's values for their matched fields.
while (this.reader.Read()) {
T result = new T();
foreach (var match in matches)
match.Value.SetValue(result, this.reader[match.Key], null);
action(result);
}
// Go to the next result set.
this.reader.NextResult();
}
private void Read(Action-Action),其中T:class,new(){
var matches=newlinkedlist();
//读取当前结果集的元数据。
使用(DataTable schema=this.reader.GetSchemaTable()){
DataRowCollection字段=schema.Rows;
//检索目标类型的属性。
//这在功能上等同于typeof(T).GetProperties(),但是
//为提高效率,会将以前检索到的属性信息[]存储起来。
var properties=ReflectionHelper.GetProperties(typeof(T));
//尝试匹配目标类型的列。。。
foreach(属性中的PropertyInfo属性){
字符串名称=property.name;
类型类型=property.PropertyType;
//…使用当前结果集的字段。。。
foreach(字段中的数据行字段){
//…根据他们的名字和类型。
如果((字符串)字段[“ColumnName”]==名称和字段[“DataType”]==类型){
//将所有成功的匹配项存储在内存中。
matches.AddLast(新的KeyValuePair((int)字段[“ColumnOrdinal”],属性));
字段。删除(字段);
打破
}
}
}
}
//对于每一行,创建目标类型的实例并设置其
//属性设置为其匹配字段的行值。
而(this.reader.Read()){
T结果=新的T();
foreach(匹配中的变量匹配)
match.Value.SetValue(结果,this.reader[match.Key],null);
行动(结果);
}
//转到下一个结果集。
this.reader.NextResult();
}
关于方法的正确性,不幸的是我现在无法测试,我有以下问题:
IDataReader
从两个或多个结果集检索数据时,IDataReader.GetSchemaTable
是否返回所有结果集的元数据,或仅返回与当前结果集对应的元数据IDataReader.GetSchemaTable检索到的列序号是否等于索引器IDataReader[int]
使用的序号?如果没有,有没有办法将前者映射到后者
DataRowCollection
的底层数据结构?即使这个问题无法回答,至少,使用DataRowCollection.Remove()
从DataRowCollection
中删除DataRow
的渐进计算复杂性是多少IDataReader
检索特定元数据(例如,仅检索列的序号、名称和类型),而不是完整的架构表(字符串)字段[“ColumnName”]==name
中强制转换到字符串
?NET如何将碰巧包含对字符串
引用的对象
变量与字符串
变量进行比较:按引用值还是按内部数据值?(当有疑问时,我宁愿在正确性方面犯错误,也就是在演员阵容方面;但是,当我能够消除所有疑问时,我宁愿这样做。)KeyValuePair
s来表示匹配字段和属性对,但这些对不是实际的键值对。它们只是普通的2元组。然而,2.0版的.NET Framework并没有提供元组数据类型,而且,如果我要创建自己的专用元组,我仍然不知道在哪里声明它。在C++中,最自然的地方是方法里面。但这是C#,在方法中类型定义是非法的。我该怎么办?处理使用根据定义不是最合适的类型(KeyValuePair
)的不雅问题,或者处理无法在最适合的位置声明类型的问题我可以回答以下几个问题: A2)是的,
GetSchemaTable
中的列序号与索引器中使用的列序号相同
B1)我不确定,但这无关紧要,因为如果在foreach
中枚举数据行集合时从数据行集合中删除它,则会抛出。如果我是你,我会制作一个字段或属性的哈希表来帮助匹配它们,而不是担心这种线性搜索和删除
编辑:我错了,这是一个谎言——正如爱德华多在下面指出的,它不会抛出。但是,如果你认为你可能有一个拥有超过几十个属性的类型,那么它仍然有点慢
C2)是的,这是必要的,否则它将通过引用进行比较
C3)无论如何,我倾向于使用KeyValuePair
。至于A1,我相信在IDataReader.NextResult()
被envoke之前,GetSchemaTable
只会返回当前结果集的信息
然后,当NextResult()
被envoked时,您必须再次执行GetSchemaTable
以获取有关当前结果集的信息
HTH.关于B1),我认为从foreach
中的集合中删除元素是有效的,只要程序不继续下一次迭代。至少,迭代器是如何在C++中工作的。哦,实际上我没有意识到这一点。你说得对。我确定了我的答案。