将 SqlDataReader 写入 XML 文件
Write SqlDataReader to XML file
我正在测试 C# 中存储的 SQL 过程。 procs return 数据类型 SqlDataReader,我想将整个内容写入 XML 文件以便稍后比较。我读过的任何内容都没有提供非常简单的解决方案。有没有办法在不循环遍历流中的所有数据的情况下执行此操作?我对 SQL 了解不多,所以我不确定我在这里工作的确切内容。
试试这个
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"C:\temp\test.xml";
static void Main(string[] args)
{
string connstr = "Enter your connection string here";
string SQL = "Enter your SQL Here";
SqlDataAdapter adapter = new SqlDataAdapter(SQL, connstr);
SqlCommand cmd = adapter.SelectCommand;
cmd.Parameters.Add("abc", SqlDbType.VarChar);
adapter.SelectCommand.ExecuteNonQuery();
DataSet ds = new DataSet();
adapter.Fill(ds);
ds.WriteXml(FILENAME, XmlWriteMode.WriteSchema);
}
}
}
由 DataSet
、DataTable
及其同类作品制作的 XML 从人们阅读它的角度来看还有一些不足之处。我会自己动手。
一个SqlDataReader
(无论它是从存储过程还是从纯文本SQL查询返回数据都没有关系),returns 0到很多结果集。每个这样的结果集都有
- 描述每一行中返回的列的模式,并且
- 结果集本身,包含零个或多个 行。
- 每一行本质上是一个包含 1 个或多个 列的数组,每个单元格包含在行中具有该序号位置的列的值。
- 每个这样的列都有特定的属性,一些来自架构,例如名称、序号类型、可空性等。
- 最后,一行中的列值是
object
类型对应于结果中列的 SQL 服务器数据类型...或 DbNull.Value
如果该列为空。
基本循环非常简单(MSDN 中有很多关于如何做的示例。)虽然一开始编写它可能需要一些工作,但一旦编写完成,它就是全面可用,所以它是一次性的。我建议这样做:
确定您希望 XML 的外观。假设你的意图是能够不时地区分结果,我可能会选择看起来像这样的东西(因为我喜欢保持简洁并避免冗余):
<stored-procedure-results>
<name> dbo.some-stored-procedure-name </name>
<result-sets>
<result-set>
<column-schema column-count="N">
<column ordinal="0...N-1" name="column-name-or-null-if-column-is-unnamed-or-not-unique" data-type=".net-data-type" nullable="true|false" />
...
</schema>
<rows>
<row>
<column ordinal="0..N-1" value="..." />
...
<row/>
...
</rows>
</result-set>
...
</result-sets>
</stored-procedure-results>
构建 POCO 模型 类 以包含数据。使用 XML 序列化属性对它们进行属性化以获得您想要的标记。从上面的 XML 示例中,这些 类 不会那么复杂。您可能希望将列值表示为字符串而不是本机数据类型。
构建一个映射器,它将 运行 数据 reader 并构建您的模型。
然后是几十行代码来构建选择的 XML 序列化器并输出格式良好的 XML.
备注:
出于 QA 目的,您可能希望捕获传递给查询的参数(如果有)以及查询本身,可能 date/time 运行.
在一些奇怪的情况下,我描述的结果集模型可能会变得……不稳定。例如,使用 compute by
的 select 语句必须以不同方式处理。根据我的经验,忽略这种边缘情况是非常安全的,因为你不太可能在野外遇到这样的查询。
想想你如何在 XML 中表示 null
:null
字符串 与 相同=41=]空个字符串。
我看到主要问题是如何在发布前测试复杂的存储过程,而不是从 SQLDataAdapter 编写 XML,这可能非常简单。逐行,逐列。
您有一个不包含静态数据的测试数据库,并且以某种方式存储了不同版本的存储过程。
一个简单的设置是 运行 您拥有的存储过程的(比方说 5)个版本,运行 它们与同一个
数据库内容,将 xml 存储到一个文件夹并进行比较。例如,我会为每个 运行 使用不同的文件夹,并有一个时间戳来区分它们。我不会在 xml 的编写方式上花太多时间,为了检测它们是否不同,您最终甚至会使用 String.Compare(fileStream1.ReadToEnd(), fileStream2.ReadToEnd())。如果结果太大,则更详细一些。
如果 2 个 xml 之间存在差异,那么您可以使用文本比较工具查看它们。 ...对于具有多个连接的更复杂的存储过程,最常见的区别可能是 xml 的大小\返回的行数,而不是字段的值。
在生产中,数据库的内容不是静态的,所以做这种类型的测试没有意义。
如所述,使用DataTable或DataSet中的内置方法WriteXml序列化SqlDataReader时,数据包含地理数据,地理数据丢失 之后无法恢复。
有关详细信息,请阅读
without loss of data and save to xml using the same built-in methods WriteXml. Try it online
提供了一种保存到 xml 的解决方法
我正在测试 C# 中存储的 SQL 过程。 procs return 数据类型 SqlDataReader,我想将整个内容写入 XML 文件以便稍后比较。我读过的任何内容都没有提供非常简单的解决方案。有没有办法在不循环遍历流中的所有数据的情况下执行此操作?我对 SQL 了解不多,所以我不确定我在这里工作的确切内容。
试试这个
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"C:\temp\test.xml";
static void Main(string[] args)
{
string connstr = "Enter your connection string here";
string SQL = "Enter your SQL Here";
SqlDataAdapter adapter = new SqlDataAdapter(SQL, connstr);
SqlCommand cmd = adapter.SelectCommand;
cmd.Parameters.Add("abc", SqlDbType.VarChar);
adapter.SelectCommand.ExecuteNonQuery();
DataSet ds = new DataSet();
adapter.Fill(ds);
ds.WriteXml(FILENAME, XmlWriteMode.WriteSchema);
}
}
}
由 DataSet
、DataTable
及其同类作品制作的 XML 从人们阅读它的角度来看还有一些不足之处。我会自己动手。
一个SqlDataReader
(无论它是从存储过程还是从纯文本SQL查询返回数据都没有关系),returns 0到很多结果集。每个这样的结果集都有
- 描述每一行中返回的列的模式,并且
- 结果集本身,包含零个或多个 行。
- 每一行本质上是一个包含 1 个或多个 列的数组,每个单元格包含在行中具有该序号位置的列的值。
- 每个这样的列都有特定的属性,一些来自架构,例如名称、序号类型、可空性等。
- 最后,一行中的列值是
object
类型对应于结果中列的 SQL 服务器数据类型...或DbNull.Value
如果该列为空。
基本循环非常简单(MSDN 中有很多关于如何做的示例。)虽然一开始编写它可能需要一些工作,但一旦编写完成,它就是全面可用,所以它是一次性的。我建议这样做:
确定您希望 XML 的外观。假设你的意图是能够不时地区分结果,我可能会选择看起来像这样的东西(因为我喜欢保持简洁并避免冗余):
<stored-procedure-results> <name> dbo.some-stored-procedure-name </name> <result-sets> <result-set> <column-schema column-count="N"> <column ordinal="0...N-1" name="column-name-or-null-if-column-is-unnamed-or-not-unique" data-type=".net-data-type" nullable="true|false" /> ... </schema> <rows> <row> <column ordinal="0..N-1" value="..." /> ... <row/> ... </rows> </result-set> ... </result-sets> </stored-procedure-results>
构建 POCO 模型 类 以包含数据。使用 XML 序列化属性对它们进行属性化以获得您想要的标记。从上面的 XML 示例中,这些 类 不会那么复杂。您可能希望将列值表示为字符串而不是本机数据类型。
构建一个映射器,它将 运行 数据 reader 并构建您的模型。
然后是几十行代码来构建选择的 XML 序列化器并输出格式良好的 XML.
备注:
出于 QA 目的,您可能希望捕获传递给查询的参数(如果有)以及查询本身,可能 date/time 运行.
在一些奇怪的情况下,我描述的结果集模型可能会变得……不稳定。例如,使用
compute by
的 select 语句必须以不同方式处理。根据我的经验,忽略这种边缘情况是非常安全的,因为你不太可能在野外遇到这样的查询。想想你如何在 XML 中表示
null
:null
字符串 与 相同=41=]空个字符串。
我看到主要问题是如何在发布前测试复杂的存储过程,而不是从 SQLDataAdapter 编写 XML,这可能非常简单。逐行,逐列。 您有一个不包含静态数据的测试数据库,并且以某种方式存储了不同版本的存储过程。 一个简单的设置是 运行 您拥有的存储过程的(比方说 5)个版本,运行 它们与同一个 数据库内容,将 xml 存储到一个文件夹并进行比较。例如,我会为每个 运行 使用不同的文件夹,并有一个时间戳来区分它们。我不会在 xml 的编写方式上花太多时间,为了检测它们是否不同,您最终甚至会使用 String.Compare(fileStream1.ReadToEnd(), fileStream2.ReadToEnd())。如果结果太大,则更详细一些。 如果 2 个 xml 之间存在差异,那么您可以使用文本比较工具查看它们。 ...对于具有多个连接的更复杂的存储过程,最常见的区别可能是 xml 的大小\返回的行数,而不是字段的值。
在生产中,数据库的内容不是静态的,所以做这种类型的测试没有意义。
如
有关详细信息,请阅读