为什么第二个查询会生成"将请求发送到服务器时发生传输级别错误"信息?

时间:2014-08-15 15:42:01

标签: c# sql-server

我们的代码使用以下代码向数据库发送查询报告:

    public DataTable RunQuery(QueryDatabase queryDatabase, string theQuery, IEnumerable<DatabaseParameter> parameters, IEnumerable<DbParameterList> listParameters)
    {
        try
        {
            using (SqlConnection connection = new SqlConnection(ConnectionString(queryDatabase)))
            {
                connection.Open();

                using (System.Data.SqlClient.SqlCommand cmdToExecute = new System.Data.SqlClient.SqlCommand())
                {
                    cmdToExecute.CommandText = theQuery;
                    cmdToExecute.CommandType = CommandType.Text;
                    cmdToExecute.CommandTimeout = 900;
                    foreach (DatabaseParameter p in parameters)
                    {
                        cmdToExecute.Parameters.Add(p.AsSqlParameter());
                    }
                    foreach (DbParameterList l in listParameters)
                    {
                        l.AddToCommand(cmdToExecute);
                    }
                    using (System.Data.SqlClient.SqlDataAdapter adapter = new System.Data.SqlClient.SqlDataAdapter(cmdToExecute))
                    {

                        cmdToExecute.Connection = connection;

                        DataTable dt = new DataTable();

                        int _numberOfRowsAffected = adapter.Fill(dt);
                        return (dt);
                    }
                }
            }
        }
        catch (Exception e)
        {
            Log.LogError("DatabaseService.RunQuery", e.Message);
            return null;
        }
    }

这对我们来说效果很好。实际上,未显示的是,通过对同一方法的另一次调用(Transactional与Reporting数据库),可以很好地从数据库中提取连接字符串。

最近,出于业务需求,我们遇到了SQL Server的一个限制:表中只能有大约300列。一份报告在临时表中生成约700列。这样做不行,所以我决定将结果拆分成几个查询并将结果表拼接在代码中(谢谢微软,我不应该这样做)。

代码如下所示:

        DataTable result = DatabaseService.Instance.RunQuery(QueryDatabase, Query, Parameters, ListParameters);
        resetSlicer();
        IList<T> paramterSlice = getParameterSlice();
        while (paramterSlice.Count > 0)
        {
            DataTable slice = getSlice(paramterSlice);
            result.AppendTableColumns(slice, KeyColumns);
            paramterSlice = getParameterSlice();
        }

getSlice()调用包含另一个“RunQuery()”调用。

当我运行此代码时,首先调用“GetSlice()”失败,但出现以下异常:

A transport-level error has occurred when sending the request to the server. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)

堆栈跟踪如下:

at System.Data.SqlClient.TdsParser.TdsExecuteRPC(_SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc, Boolean sync, TaskCompletionSource`1 completion, Int32 startRpc, Int32 startParam)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
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 <Anonymized>.Common.Database.DatabaseService.RunQuery(QueryDatabase queryDatabase, String theQuery, IEnumerable`1 parameters, IEnumerable`1 listParameters) 

为了尝试诊断问题,我注释掉了第一个“RunQuery()”调用。这导致第一个“getSlice()”正确返回结果;但是,第二次调用失败并出现同样的错误。

鉴于我们已经能够在代码中的其他地方使用此模式运行多个查询,为什么这个特定用法会产生错误?

1 个答案:

答案 0 :(得分:0)

帽子提示Mark Peters指向正确的方向。

存在DbParameterList以将列表传递给SQL(例如,尝试在单个语句中查找姓氏为#34; Smith&#34;,&#34; Doe&#34;或&#34; Jones&#34; )。这避免了在SQL中使用插值IN(...)列表的丑陋构造。为此,该类实现IEnumerable接口。我假设微软会正确使用自己的接口。在这种情况下,我假设在枚举IEnumerable之前,他们会调用IEnumerable上的Reset()方法。但是,他们没有。

第一次调用DbParameterList时,枚举器处于开头且一切正常。第二次调用会使连接崩溃(是的,如果在SqlParameter中使用的IEnumerable为空,则连接崩溃),因为枚举器从未被重置。

因此,在枚举器附加到SqlCommand时添加一个Reset()调用可以解决问题。