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]);
}

然后,问题就解决了! 甚至性能都很好,但是,我测试过的表相对较小。稍后我将有机会在更大的卷上对其进行测试,让我们看看。