Our code uses the following code to send queries to the database for our reports:
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;
}
}
This has been working well for us. In fact, not shown is that the connection string may very well be pulled from the database by another call to this same method (Transactional versus Reporting databases).
Recently, for business requirements, we ran into one of SQL Server's limits: You can only have ~300 columns in a table. One report was generating ~700 columns in a temporary table. That won't work, so I decided to split the result into several queries and splice the resulting tables in code (Thank you Microsoft, I shouldn't have to do that).
The code looks like the following:
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();
}
The getSlice() call contains another "RunQuery()" call.
When I run this code, first call to "GetSlice()" fails with the following exception:
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.)
The stack Trace is as follows:
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)
To try to diagnose the problem I commented out the first "RunQuery()" call. This resulted in the first "getSlice()" returning the results correctly; however, the second call failed with the same error.
Given that we have been able to run multiple queries using this pattern elsewhere in the code, why would this particular usage be generating an error?