【发布时间】:2018-10-19 00:33:59
【问题描述】:
我一直致力于以流的形式提供对大型 SQL 结果的访问,特别是当查询使用 for json 或 for xml 子句时。
我注意到,当查询返回 json 或 xml 时,SqlDataReader 不允许使用 GetStream() 方法,这是文档所预期的:
'对列 'c' 的 GetStream 尝试无效。 GetStream 函数只能用于 Binary、Image、Udt 或 VarBinary 类型的列。'
但是,它确实允许使用GetBytes()。
返回数据为varchar(max) 或nvarchar(max) 时的行为相同。 GetStream() 不起作用,但 GetBytes() 会。
对于常规的、长度有限的 varchar 或 nvarchar 列,既不允许使用 GetStream 也不允许使用 GetBytes。
能够调用GetBytes 意味着我已经能够相当容易地构建一个自定义SqlTextStream : Stream 类,但前提是从nvarchar 读取时最好以2 的倍数读取字节,以免将字符撕成两半。
我查看了SqlDataReader.GetColumnSchema() 提供的信息,但没有发现为什么GetBytes 被允许针对n/varchar(max) 结果的明显原因。我可能遗漏了一些东西,但是对于常规或(最大)字符数据,GetColumnSchema 的输出似乎相同,但长度除外。
有谁知道为什么GetBytes 被允许针对n/varchar(max) 列?你认为依赖GetBytes 被允许是安全的吗?
下面是一些简单的测试代码:
public void Test()
{
var cmd1 = "select c = 'getbytes permitted here' for json path";
var cmd2 = "select c = cast('getbytes also permitted here' as nvarchar(max))";
var cmd3 = "select c = cast('getbytes not permitted here' as nvarchar(32))";
using (var con = new SqlConnection("data source=theDB; initial catalog=playground; integrated security=SSPI"))
// switch between cmd1, cmd2 and cmd3 to see the different behaviour.
using (var cmd = new SqlCommand(cmd1, con))
{
con.Open();
using (var rdr = cmd.ExecuteReader(System.Data.CommandBehavior.SequentialAccess))
{
var o = rdr.GetColumnSchema();
var buffer = new byte[128];
rdr.Read();
//System.IO.Stream s = rdr.GetStream(0); this is never permitted
rdr.GetBytes(0, 0, buffer, 0, buffer.Length); // this is permitted for cmd1 and cmd2
}
}
}
【问题讨论】:
-
你能解释一下
wrap up这个词的含义吗?这里的动机是什么?是性能吗?请澄清您的问题... -
我认为这是一个有趣但可能无法回答的问题;如果有的话,它会提示“那是什么编码?”的问题;我原以为
GetChars和TextReader会是在这里实现的更可靠的API... -
将“总结”更改为“提供访问权限”。动机是表现,是的。当我考虑通过 PushStreamContent 将流推送到 httpClients 时,我开始走这条路,中间可能有一个 GZipStream。但我想我不妨将数据访问流返回的代码从中分离出来,所以我创建了一个派生自流的数据访问类。我认为它在其他场景中也可能有用。
-
Marc - 是的,GetChars 或 GetTextReader 肯定会工作,即使结果不是(最大)类型,但由于它们会得到 char[],而不是 byte[],因此需要进行转换执行以将结果公开为流。不是很糟糕,而且我确实有一个
Stream.Read()实现可以做到这一点 - 这实际上是我的第一个方法。但我很好奇并开始探索选项,这就是我遇到这种行为的原因。 -
@allmhuran -
char[]会更自然。当客户端数据库驱动程序将结果传送到 ADO.Net 时,我相当肯定任何文本都将被处理为 UTF-16。
标签: c# sql-server stream sqldatareader