以下是我的代码,我将一个存储过程作为SQL执行,它运行多个Select语句。现在每个datareader.NextResult()的输出将是一个不同的对象(一个POCO类),它们将不依赖(因此我不能有一个接口/基类来访问它们)。这种方法的问题是我必须在SelectQuery返回的列表上进行类型转换。有没有更好的方法来实现以下,以便我可以避免类型转换?
public IEnumerable<IEnumerable<T>> SelectQuery<T>(string strSql, List<Func<IDataRecord, T>> infoExtractors)
{
var result = new List<List<T>>();
using (var connection = GetDBConnection())
{
using (var command = GetDBCommand(strSql))
{
command.Connection = connection;
connection.Open();
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
try
{
int i = 0;
List<T> curList = new List<T>();
result.Add(curList);
while (reader.Read())
{
curList.Add(infoExtractors[i](reader));
}
while(reader.NextResult())
{
i++;
curList = new List<T>();
result.Add(curList);
while (reader.Read())
{
curList.Add(infoExtractors[i](reader));
}
}
}
finally
{
reader.Close();
}
}
}
}
return result;
}
此代码的主要目的是避免让调用者关闭数据库连接
以下是我编写的示例代码,用于模拟此操作并检查是否可以避免类型转换
class Program
{
static void Main(string[] args)
{
List<Func<int, object>> lst = new List<Func<int, object>>();
lst.Add(c1.SetThis);
lst.Add(c2.SetThis);
lst.Add(c3.SetThis);
var output= Check(lst);
foreach(var cur in output)
{
foreach(var innerCur in cur)
{
System.Console.Write(innerCur);
}
System.Console.WriteLine();
}
System.Console.ReadLine();
}
static List<List<T>> Check<T>(List<Func<int, T>> inpList)
{
List<List<T>> lst = new List<List<T>>();
lst.Add(new List<T>() { inpList[0](10) });
lst.Add(new List<T>() { inpList[1](20) });
lst.Add(new List<T>() { inpList[2](30) });
return lst;
}
}
class c1
{
internal int num;
internal static c1 SetThis(int i)
{
c1 c1Obj= new c1();
c1Obj.num = i;
return c1Obj;
}
}
class c2
{
internal int num;
internal static c2 SetThis(int i)
{
c2 c2Obj = new c2();
c2Obj.num = i;
return c2Obj;
}
}
class c3
{
internal int num;
internal static c3 SetThis(int i)
{
c3 c3Obj = new c3();
c3Obj.num = i;
return c3Obj;
}
}
现在,虽然测试样本具有相同的方法名称,但实际上类c1,c2,c3将保存不同的数据。另外 innerCur 的内部foreach循环打印类型,但我需要一种方法来获取值而不使用类型转换?可能吗?在最坏的情况下,我将不得不摆脱以下内在的foreach
foreach(var innerCur in cur)
{
System.Console.Write(innerCur);
}
与
foreach (var innerCur in cur)
{
if(innerCur is c1)
System.Console.Write((innerCur as c1).num);
else if(innerCur is c2)
System.Console.Write((innerCur as c2).num);
else
System.Console.Write((innerCur as c3).num);
}
答案 0 :(得分:0)
一个有趣的问题。我能想到的唯一解决方案是在Generic Repository类中使用反射来调用已传入的泛型Type上的方法。
通过让库的使用者编写一个与他们正在查询的DataBase和Tables相匹配的类来解决问题,包括将数据行转换为对象的函数以及由该函数填充的List。
用户将此对象传递给GetData方法,并由结果填充。
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ThierCode
{
public class MyTableQuery : YourLibrary.IMultiTableQuery
{
public Dictionary<string, string> MethodNameAndSql { get; set; }
public void PopulateMyObjects(IDataRecord dr)
{
MyObject o = new MyObject();
o.Name = dr["Name"].ToString();
this.MyObjects.Add(o);
}
public List<MyObject> MyObjects { get; set; }
}
public class MyObject
{
public string Name { get; set; }
}
}
namespace YourLibrary
{
public interface IMultiTableQuery
{
public Dictionary<string, string> MethodNameAndSql { get; set; }
}
public class Repo<T> where T : IMultiTableQuery
{
public void GetData(T inputClass)
{
Type type = typeof(T);
foreach (var kvp in inputClass.MethodNameAndSql)
{
string sql = kvp.Value;
//run sql and get datareader
//get the populate method back from the dictionary
MethodInfo methodInfo = type.GetMethod(kvp.Key);
while (reader.Read())
{
// execute via reflection
methodInfo.Invoke(inputClass, reader);
}
}
}
}
}