4

我知道通常推荐的从存储过程填充 DataSet 实例的方法是使用 SqlDataAdapter.Fill(DataSet)。我能找到的每个答案都说要以开箱即用的方式使用它。我通常会同意,它工作得很好。

但是,当您需要处理存储过程输出和 DataSet 输入之间的数据时,它就会崩溃。具体来说,当在输出中使用自定义 CLR 类型时,它会中断使用 CLR的列的列索引InvalidOperationException: DataReader.GetFieldType(n) returned null.在哪里n(在其中一个表中;似乎没有明显的方法可以告诉列索引引用哪个表)输入它的输出。这是可以理解的,因为读者不知道相关列中的数据类型。

我可以打破CLR类型的反序列化逻辑并在两个地方使用它,我似乎没有时间在Fill()发生故障之前调用任何这样的反序列化方法。

我知道SqlCommand.ExecuteReader(),但似乎只能从那张桌子中取出一张桌子。

有问题的 CLR 类型旨在用更严格的内容替换核心系统字段之一(当前存储为自由格式文本)。遍历数据库并向此类字段的每个返回实例添加方法调用的问题已被讨论为一种可能性,但肯定是一项不平凡的工作。因此,人们认为可以在 DAL 中进行转换(只要求可以以编程方式识别这些列,这是可行的),从而使存储对客户端透明,并且客户端对数据的使用对数据库仍然透明。

因此:如何在不使用 SqlDataAdapter.Fill() 的情况下访问存储过程输出中的所有表?或者,我如何挂钩 SqlDataAdapter.Fill() 的执行以在 SP 的执行和填充 DataSet 之间进行手动处理?

4

2 回答 2

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]);
                }
            }
        }
    }
}
于 2012-11-12T09:16:16.677 回答
0

看起来它实际上比我想象的要容易。虽然Tim Schmelter 的回答让我进行了实验,但真正的诀窍是简单地将 CLR 类型程序集添加到 DAL 项目中。然后一切都到位了SqlDataAdapter.Fill(DataSet); 突然之间,它知道如何处理从 SQL Server 接收到的二进制数据,显然(未经验证,但合理)调用类型的ToString(). 我还没有验证当 DAL 代码创建一个在其他地方使用的 DataSet 时会发生什么,但在这两者之间,我认为有可能提出一个可行的解决方案。

于 2012-11-23T11:52:37.067 回答