0

因此,在将 MySqlDataReader 与 BLOB 列一起使用时,我遇到了臭名昭著的IndexOutOfRangeException 。我的情况虽然很具体。故事如下。我首先通过执行命令获取 MySqlDataReader,然后将其传递给 SqlBulkCopy 以进行“流式”批量插入,从而将数据从 MySQL 拉入 SQL Server。代码简单明了:

    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 是密封的,因此无法从它继承。所以,我正在考虑使用装饰器模式并喜欢:

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() 呢?即在我的 MySqlDataReaderFixed 类中应该有什么:

    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?

4

1 回答 1

0

事实证明,我必须先看一个“步骤”。SqlBulkCopy 实际上调用了 GetStream() 方法,而后者又调用了麻烦制造者 GetBytes()。所以,我在我的装饰器类中覆盖了 GetStream() 如下(取自这里):

public override Stream GetStream(int ordinal)
{
    return new MemoryStream((byte[])mySqlDataReader[ordinal]);
}

而且,问题消失了!甚至性能都很好,但是,我测试过的表相对较小。稍后我将有机会在更大的数量上对其进行测试,让我们拭目以待。

于 2021-01-16T23:47:14.813 回答