我知道通常建议的从存储过程填充DataSet实例的方法是使用SqlDataAdapter.Fill(DataSet)。我能找到的每个答案都说它以开箱即用的方式使用它。我通常会批准它,效果很好。
但是,当您需要在存储过程输出和DataSet输入之间处理数据时,它会崩溃。具体来说,当在输出中使用自定义CLR类型时,它会以InvalidOperationException: DataReader.GetFieldType(n) returned null.
为中断,其中n
是列的列索引(在其中一个表中;似乎没有明显的方法可以告诉它table the column index references)在其输出中使用CLR类型。这是可以理解的,因为读者不知道相关列中的数据类型。
我可以打破CLR类型的反序列化逻辑并在两个地方使用它,但是在Fill()发生故障之前我似乎没有时间调用任何这样的反序列化方法。
我知道SqlCommand.ExecuteReader()
,但只能看到一张表。
有问题的CLR类型旨在用一些更严格的内容替换其中一个核心系统字段(目前存储为自由格式文本)。已经讨论了通过数据库并向这样一个字段的每个返回实例添加方法调用的问题作为一种可能性,但肯定是一项非常重要的工作量。所以有人认为转换可以在DAL中完成(只需要以编程方式识别这些列,这是可行的),使存储对客户端和客户端使用数据仍然透明对数据库透明。
因此:如何在不使用SqlDataAdapter.Fill()的情况下访问存储过程输出中的所有表? 或者,如何挂钩执行SqlDataAdapter.Fill()以在执行SP和填充DataSet之间进行手动处理?
答案 0 :(得分:2)
您可以选择多个DataReader
的表格。您可以使用reader.NextResult
检查是否有更多结果集并将数据阅读器推进到它:
using (var con = new SqlConnection(Properties.Settings.Default.ConnectionString))
{
using (var cmd = new SqlCommand("StoredProcedureName", con))
{
cmd.CommandType = CommandType.StoredProcedure;
int rowCount = 0;
con.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine("Object 1 in Row {0}: '{1}'", ++rowCount, rdr[0]);
}
if (rdr.NextResult())
{
rowCount = 0;
while (rdr.Read())
{
Console.WriteLine("Object 1 in Row {0}: '{1}'", ++rowCount, rdr[0]);
}
}
}
}
}
答案 1 :(得分:0)
看起来它实际上比我想象的要容易。虽然Tim Schmelter's answer让我进行了实验,但真正的诀窍是简单地将CLR类型程序集添加到DAL项目。然后一切都与SqlDataAdapter.Fill(DataSet)
落在一起;突然之间,它知道如何处理从SQL Server收到的二进制数据,显然(未经验证,但似乎合理)调用类型ToString()
。我还没有验证当DAL代码创建一个在别处使用的DataSet时会发生什么,但在这两者之间,我认为有可能提出一个可行的解决方案。