【问题标题】:Retry DbDataAdapter.Fill after reconnection重新连接后重试 DbDataAdapter.Fill
【发布时间】:2015-05-22 06:03:07
【问题描述】:

我有一个代码来使用带有 select sql 和 DbDataAdapter 的 SqlCommand 从 db 填充 DataTable。在向 DataTable 填充行期间,有时会丢失 DbConnection,这会被处理并调用 adapter.Fill() 的第二次尝试:

int FillSafe(DataTable dataTable)
{
    try
    {
        return adapter.Fill(dataTable);
    }
    catch (Exception ex)
    {
        if (connectionErrorManager.HandleDisconnectionAndSecurityErrors(ex))
        {
            // Re-try fill function if error was properly handled
            return adapter.Fill(dataTable);
        }

        throw;
    }
}

适配器是使用命令初始化的本地字段:

adapter = new SqlDataAdapter((SqlCommand)selectCommand);

而connectionErrorManager.HandleDisconnectionAndSecurityErrors()基本上是关闭再重新打开SqlConnection对象(同一个实例)。

它似乎工作正常,但没有主键的表存在问题 - 某些数据行在 DataTable 中变得重复。 IE。以下测试以 5 行而不是 3 行失败:

public void TestFillDoesnotProduceDuplicateRowsAfterDisconnect()
{
    const string Query = @"
SELECT 'A'
UNION ALL
SELECT 'B'
UNION ALL
SELECT 'C'";

    var table = new DataTable();
    table.RowChanged += (o, e) =>
    {
        if (table.Rows.Count == 2)
        {
            Db.Connection.CloseConnection();
        }
    };

    using (var command = Db.Connection.Command(Query))
    using (var adapter = command.NewDataAdapter())
    {
        FillSafe(table);
    }

    AssertEquals(3, table.Rows.Count);
}

如果我在重新填充数据表之前尝试清除它

table.Rows.Clear();

测试失败,关闭 DataReader 出现异常:

Exception Type: System.InvalidOperationException
Message: Invalid attempt to call Read when reader is closed.
StackTrace:
at System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)
at System.Data.SqlClient.SqlDataReader.Read()
at System.Data.Common.DataAdapter.FillLoadDataRow(SchemaMapping mapping)
at System.Data.Common.DataAdapter.FillFromReader(DataSet dataset, DataTable datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn parentChapterColumn, Object parentChapterValue)
at System.Data.Common.DataAdapter.Fill(DataTable[] dataTables, IDataReader dataReader, Int32 startRecord, Int32 maxRecords)
at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.Fill(DataTable[] dataTables, Int32 startRecord, Int32 maxRecords, IDbCommand command, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.Fill(DataTable dataTable)
at className.FillSafe[T](DataTable dataTable)
at className.TestFillDoesnotProduceDuplicateRowsAfterDisconnect()

所以我有两个问题:

  1. 为什么 table.Rows.Clear() 会导致这种行为差异?它是如何关闭 DataReader 的?

  2. 如何解决?我需要清除已经加载的行并重新填充表格。

【问题讨论】:

  • 似乎 table.Rows.Clear() 不会关闭适配器/命令上的读取器,而是关闭表本身的某个位置,因为在重新连接后(以及在清除原始行后)使用新的 DataTable 重新填充table) 完成时没有错误。

标签: c# sql-server ado.net


【解决方案1】:

好的,我找到了问题,它在我的测试代码中。 我在加载特定行数时手动关闭了连接,在清理表和重新填充后,连接再次关闭,触发新的未处理异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-28
    • 2013-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-24
    • 2012-08-07
    相关资源
    最近更新 更多