【发布时间】:2014-10-09 08:56:51
【问题描述】:
我们的代码使用以下代码向数据库发送查询以获取我们的报告:
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;
}
}
这对我们来说效果很好。事实上,没有显示的是连接字符串很可能通过对同一方法的另一个调用(事务数据库与报告数据库)从数据库中提取出来。
最近,出于业务需求,我们遇到了 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()”正确返回结果;但是,第二次调用失败并出现同样的错误。
鉴于我们已经能够在代码的其他地方使用这种模式运行多个查询,为什么这种特殊用法会产生错误?
【问题讨论】:
-
"一个表中只能有 ~300 列。" - 如果一个表中有大约 300 列,那么它很有可能是错误的
-
请注意,我说的是临时表(实际上是优化器生成的)。由于业务需求,查询的输出可能是那么多列,我无能为力。
-
我注意到您正在将 SqlCommand 添加到每个 DBParameterList 中,可能是出于某种日志记录/跟踪原因?但是,这些 SqlCommand 将在您可以使用它们时被处理掉。此外,他们可能正在处理附加的 SqlParameters。您可以尝试重用 Disposed 参数吗?
-
DBParameterList 使用该惯用语是因为我在了解扩展方法之前就编写了它,而扩展方法实际上就是该方法。 DbParamterList 封装了一个 SqlParameter 的信息,它有一个值列表作为它的“值”。我将审查该代码是否存在可能的重用问题。
标签: c# sql-server