0

First off, prior to asking this question I have been researching connection pooling for the better part of my morning. What I've found is that is turned on by default, handled by the application/system, and C#'s System.Data.X namespaces (where X is something like OLEDBConnection / SqlConnection ) handles it automatically.

But as I'm still new to the whole database access and pooling, I am looking for clarification since I wrote a class to handle connections at a higher level.

public abstract class AbstractDatabase<T> where T: where T : System.Data.Common.DbConnection
{
   // Take this class's connection string and return a new connection object
   public abstract T GetConnection();
   
   public abstract SqlKata.Compilers.Compiler { get; }


   // Compile the query and return a DataTable
   // This is actually pointing to a static method that uses the IDBConnection interface and logs any errors, but I copied the relavant code here
   public virtual DataTable GetDataTable(SqlKata.Query query)
   {
      using (var Conn = GetConnection())
      {
         if (Conn.State == ConnectionState.Closed) Conn.Open();
         using (var Cmd = Conn.CreateCommand())
         {
            Cmd.CommandType = CommandType.Text;
            Cmd.Connection = Conn;
            Cmd.CommandText = Compiler.Compile(Query).ToString(); // the query is fully formed string here
            Cmd.Parameters.AddDummyParameter(); // I noticed that without any parameters, this didn't work, so this method adds a dummy, even if the string doesn't have any '?' characters
            using (var DR = Cmd.ExecuteReader())
            {
               DataTable DT = new DataTable();
               DT.Load(DR);
               return DT;
            }   
         }
      }
   }
}

public class SomeDatabase : AbstractDatabase<OleDbConnection> 
{ 
    // class implementation 
} 

here is my question:

If I were to somewhere else in my program do something like this:

DataTable Tbl1 = SomeDatabase.GetDataTable(Query1);
DataTable Tbl2 = SomeDatabase.GetDataTable(Query2);
....
DataTable Tbl10 = SomeDatabase.GetDataTable(Query10);

My understanding is that the method's Using ( var Conn = GetConnection()) statement will automatically issue a Conn.Close() and dispose of the Conn as the method exits. But connection pooling is automatically enabled, so it will actually reuse that connection almost immediately instead of closing it, correct?

With that level of abstraction, does it make sense to write it like this?

using ( var conn = SomeDatabase.GetConnection())
{
   DataTable Tbl1 = SomeDatabase.GetDataTable(Query1);
   ....
   DataTable Tbl10 = SomeDatabase.GetDataTable(Query10);
}
  • Would this make any difference?
  • Should the method be written to accept the connection that already open ?
  • Should the class be written to use the same connection object itself, rather than calling GetConnection() every time ? ( for example, a get-only property that initializes the backing field on first request to it, then all subsequent requests actually receive the backing field's object)
RFBomb
  • 51
  • 6
  • Does this answer your question? [C# Data Connections Best Practice?](https://stackoverflow.com/questions/17552829/c-sharp-data-connections-best-practice) – Charlieface Jul 21 '22 at 13:45
  • 1
    In rare situations, mainly when performance is an issue, then yes it's worth it. Otherwise the extra complexity of passing an external connection isn't worth it, just create a new connection and dispose with `using`. And `if (Conn.State == ConnectionState.Closed)` is unnecessary in that case. Consider also retrieving all three resultsets in a single batch using `DR.NextResult()` – Charlieface Jul 21 '22 at 13:46
  • For most of the calls, the database will reside local on the user's pc, so for those the performance really isn't a concern. But the primary database the local db is synced from (read-only) will be remote. Most users will have to VPN into the home office then initiate the database sync to update their local db with latest info. Hence this question, since re-opening over the remote connection is likely going to be slow, and I wanted to alleviate that impact if possible – RFBomb Jul 21 '22 at 14:20
  • 1
    Given connection pooling, as you rightly point out, it doesn't close and reopen the connection unless there is a big gap between calls. But it still calls `sp_reset_connection` which has a tiny perf impact. To avoid even that you can put three `SELECT`s in the same batch. – Charlieface Jul 21 '22 at 14:26
  • I haven't heard of 'batching' like you refer, nor the 'DR.NextResult()' method, and after a (quick) google didn't immediately find good examples. Would you essentially concat several 'Select' statements together to acheive that? as in `Select X from tblX; Select Y from tblY; Select Z from tblZ;` ? – RFBomb Jul 21 '22 at 14:58
  • 1
    Yes that is exactly what you do, and you loop both [`NextResult`](https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqldatareader.nextresult?view=dotnet-plat-ext-6.0) and [`Read`](https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqldatareader.read?view=dotnet-plat-ext-6.0). If you want to call `DataTable.Load` then instead create a `DataSet` and call `Load` on that, which will call `NextResult` for you and create a set of datatables. – Charlieface Jul 21 '22 at 14:59
  • I assume the driver itself has to allow for that type of action though, because the following statement: `SELECT * FROM [tblA-Axis]; SELECT * FROM [tblB-Axis]; SELECT * FROM [tblC-Axis]; ` is generating the exception: `Characters found after end of SQL statement.`, but each individual statement in that string successfully loads the table. So while thats a pretty neat thing that may be able to be done, I'm reading from an Access database that apparently doesnt like it (using OLEDBconnection object to facilitate the connection and create the IDataReader ) – RFBomb Jul 21 '22 at 15:18
  • Definitely works with `SqlCommand` for SQL Server, not sure about `OleDb`, what driver/provider are you using in the connection string? – Charlieface Jul 21 '22 at 15:20
  • the ACE oledb provider. I saw the majority of the 'bulk' articles specifically mentioned sql server, I couldn't find anything regarding MS Access databases for bulk statements like that. But anyway, thanks for the help, makes me more confident in my high-level abstraction of the database calls – RFBomb Jul 21 '22 at 16:11
  • https://stackoverflow.com/a/2750640/14868997 – Charlieface Jul 21 '22 at 16:12

0 Answers0