如果需要以流方式从SqlServer读取数据,则可以使用某些功能。例如使用SqlDataReader
with CommandBehavior.SequentialAccess
,特别是当需要访问二进制列数据时,可以使用以下GetStream(int)
方法:
var cmd = new SqlCommand();
cmd.Connection = connection;
cmd.CommandText = @"select 0x0123456789 as Data";
using (var dr = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
dr.Read();
var stream = dr.GetStream(0);
// access stream
}
但是,当需要使用将数据馈送到SqlServer时SqlBulkCopy
,尤其是如果需要将流作为二进制列的数据源来提供数据时,如何以相反的方向流数据呢?
我尝试了以下
var cmd2 = new SqlCommand();
cmd2.Connection = connection;
cmd2.CommandText = @"create table #Test (ID int, Data varbinary(max))";
cmd2.ExecuteNonQuery();
using (SqlBulkCopy sbc = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, null))
{
sbc.DestinationTableName = "#Test";
sbc.EnableStreaming = true;
sbc.ColumnMappings.Add(0, "ID");
sbc.ColumnMappings.Add(1, "Data");
sbc.WriteToServer(new TestDataReader());
}
其中TestDataReader
实现IDataReader
如下:
class TestDataReader : IDataReader
{
public int FieldCount { get { return 2; } }
int rowCount = 1;
public bool Read() { return (rowCount++) < 3; }
public bool IsDBNull(int i) { return false; }
public object GetValue(int i)
{
switch (i)
{
case 0: return rowCount;
case 1: return new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89 };
default: throw new Exception();
}
}
//the rest members of IDataReader
}
并按预期工作。
但是改变
case 1: return new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89 };
到
case 1: return new MemoryStream(new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89 });
导致System.InvalidOperationException
消息异常
来自数据源的MemoryStream类型的给定值不能转换为指定目标列的varbinary类型。
是否有提供一个方式Stream
从IDataReader
(或可能DbDataReader
),以SqlBulkCopy
作为数据的二进制列的源极,而无需首先将所有数据复制到存储器中(字节阵列)?
不确定此文件是否在任何地方都有记录,但是如果对SqlBulkCopy
源代码进行简短检查,您可能会发现它以不同的方式对待不同的数据读取器。首先,SqlBulkCopy
它确实支持流和GetStream
,但是您可能会注意到该IDataReader
接口不包含GetStream
method。因此,当您将自定义IDataReader
实现提供给SqlBulkCopy
-时,它将不会将二进制列视为流,也不会接受Stream
类型的值。
另一方面-DbDataReader
确实有此方法。如果您提供-继承类SqlBulkCopy
的实例DbDataReader
-它将以流方式处理所有二进制列,并将调用DbDataReader.GetStream
。
因此,要解决您的问题-DbDataReader
像这样继承:
class TestDataReader : DbDataReader
{
public override bool IsDBNull(int ordinal) {
return false;
}
public override int FieldCount { get; } = 2;
int rowCount = 1;
public override bool HasRows { get; } = true;
public override bool IsClosed { get; } = false;
public override bool Read()
{
return (rowCount++) < 3;
}
public override object GetValue(int ordinal) {
switch (ordinal) {
// do not return anything for binary column here - it will not be called
case 0:
return rowCount;
default:
throw new Exception();
}
}
public override Stream GetStream(int ordinal) {
// instead - return your stream here
if (ordinal == 1)
return new MemoryStream(new byte[] {0x01, 0x23, 0x45, 0x67, 0x89});
throw new Exception();
}
// bunch of irrelevant stuff
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句