SqlBulkCopy、MySqlDataReader、BLOB 和 IndexOutOfRangeException
SqlBulkCopy, MySqlDataReader, BLOB, and IndexOutOfRangeException
因此,在将 MySqlDataReader 与 BLOB 列一起使用时,我遇到了臭名昭著的 。我的情况虽然很具体。故事如下。我通过首先从执行命令获取 MySqlDataReader,然后将其传递给 SqlBulkCopy 以进行“流式”批量插入,将数据从 MySQL 拉入 SQL 服务器。代码简单明了:
public static void BulkCopyMySqlDataReader(string destinationConnectionString, int batchSize, string destinationTableName, IEnumerable<string> sourceColumns, MySqlDataReader mySqlDataReader)
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnectionString, SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.Default))
{
bulkCopy.BulkCopyTimeout = 0;
bulkCopy.BatchSize = batchSize;
bulkCopy.DestinationTableName = destinationTableName;
bulkCopy.EnableStreaming = true;
foreach (var dataColumn in sourceColumns)
_ = bulkCopy.ColumnMappings.Add(dataColumn, dataColumn);
try
{
bulkCopy.WriteToServer(mySqlDataReader);
}
catch (Exception)
{
throw;
}
}
}
一切正常,但是,在 MySQL 方面,我有 2 个带有 BLOB 列的表,这就是问题开始的地方。加载这些表时,它会抛出:
System.IndexOutOfRangeException: Data index must be a valid index in the field
System.IndexOutOfRangeException:
at MySql.Data.MySqlClient.Interceptors.ExceptionInterceptor.Throw(Exception exception)
at MySql.Data.MySqlClient.MySqlDataReader.Throw(Exception ex)
at MySql.Data.MySqlClient.MySqlDataReader.GetBytes(Int32 i, Int64 fieldOffset, Byte[] buffer, Int32 bufferoffset, Int32 length)
因此,据我所知,SqlBulkCopy 自行决定它必须调用 GetBytes() 方法来为 BLOB 列流式传输数据,这就是我遇到此异常的地方。
出于特定原因,我必须使用 8.0.15 版的 MySql.Data 库。因此,即使它在较新的版本中得到修复,我也必须自己以某种方式处理它。我的想法是以某种方式覆盖 GetBytes() 来解决这个问题。
由于MySqlDataReader是sealed,所以无法继承。所以,我正在考虑使用 Decorator 模式并喜欢:
public sealed class MySqlDataReaderFixed : DbDataReader, IDataReader, IDisposable, IDataRecord
{
public MySqlDataReader mySqlDataReader { get; set; }
//override required methods like...
public override bool GetBoolean(int ordinal)
{
return mySqlDataReader.GetBoolean(ordinal);
}
}
那么,我该如何正确执行 GetBytes()? IE。我的 MySqlDataReaderFixed class:
中应该有什么
public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
{
var bufferLength = mySqlDataReader.GetBytes(ordinal, 0, null, 0, 0);
// what's next?
}
有人可以帮忙吗?
或者,也许还有另一种方法可以解决这个问题,考虑仍然使用 MySqlDataReader(来自 MySql.Data v 8.0.15.0)和 SqlBulkCopy?
原来我之前必须看一个“步骤”。 SqlBulkCopy 实际上调用了 GetStream() 方法,而后者又调用了麻烦制造者 GetBytes()。
因此,我在装饰器 class 中覆盖了 GetStream() 如下(取自 here):
public override Stream GetStream(int ordinal)
{
return new MemoryStream((byte[])mySqlDataReader[ordinal]);
}
然后,问题就解决了!
甚至性能都很好,但是,我测试过的表相对较小。稍后我将有机会在更大的卷上对其进行测试,让我们看看。
因此,在将 MySqlDataReader 与 BLOB 列一起使用时,我遇到了臭名昭著的
public static void BulkCopyMySqlDataReader(string destinationConnectionString, int batchSize, string destinationTableName, IEnumerable<string> sourceColumns, MySqlDataReader mySqlDataReader)
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnectionString, SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.Default))
{
bulkCopy.BulkCopyTimeout = 0;
bulkCopy.BatchSize = batchSize;
bulkCopy.DestinationTableName = destinationTableName;
bulkCopy.EnableStreaming = true;
foreach (var dataColumn in sourceColumns)
_ = bulkCopy.ColumnMappings.Add(dataColumn, dataColumn);
try
{
bulkCopy.WriteToServer(mySqlDataReader);
}
catch (Exception)
{
throw;
}
}
}
一切正常,但是,在 MySQL 方面,我有 2 个带有 BLOB 列的表,这就是问题开始的地方。加载这些表时,它会抛出:
System.IndexOutOfRangeException: Data index must be a valid index in the field
System.IndexOutOfRangeException:
at MySql.Data.MySqlClient.Interceptors.ExceptionInterceptor.Throw(Exception exception)
at MySql.Data.MySqlClient.MySqlDataReader.Throw(Exception ex)
at MySql.Data.MySqlClient.MySqlDataReader.GetBytes(Int32 i, Int64 fieldOffset, Byte[] buffer, Int32 bufferoffset, Int32 length)
因此,据我所知,SqlBulkCopy 自行决定它必须调用 GetBytes() 方法来为 BLOB 列流式传输数据,这就是我遇到此异常的地方。 出于特定原因,我必须使用 8.0.15 版的 MySql.Data 库。因此,即使它在较新的版本中得到修复,我也必须自己以某种方式处理它。我的想法是以某种方式覆盖 GetBytes() 来解决这个问题。
由于MySqlDataReader是sealed,所以无法继承。所以,我正在考虑使用 Decorator 模式并喜欢:
public sealed class MySqlDataReaderFixed : DbDataReader, IDataReader, IDisposable, IDataRecord
{
public MySqlDataReader mySqlDataReader { get; set; }
//override required methods like...
public override bool GetBoolean(int ordinal)
{
return mySqlDataReader.GetBoolean(ordinal);
}
}
那么,我该如何正确执行 GetBytes()? IE。我的 MySqlDataReaderFixed class:
中应该有什么 public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
{
var bufferLength = mySqlDataReader.GetBytes(ordinal, 0, null, 0, 0);
// what's next?
}
有人可以帮忙吗? 或者,也许还有另一种方法可以解决这个问题,考虑仍然使用 MySqlDataReader(来自 MySql.Data v 8.0.15.0)和 SqlBulkCopy?
原来我之前必须看一个“步骤”。 SqlBulkCopy 实际上调用了 GetStream() 方法,而后者又调用了麻烦制造者 GetBytes()。 因此,我在装饰器 class 中覆盖了 GetStream() 如下(取自 here):
public override Stream GetStream(int ordinal)
{
return new MemoryStream((byte[])mySqlDataReader[ordinal]);
}
然后,问题就解决了! 甚至性能都很好,但是,我测试过的表相对较小。稍后我将有机会在更大的卷上对其进行测试,让我们看看。