Browse Source

Use asynchronous data access methods in appMpower.Orm (#9281)

* Use asynchronous data access methods in  appMpower.Orm

* Improved connection pool handling

* Using tuple with base connection elements instead of "this" for pooling

* Improved caching

* Better separation of keyed and unkeyed command caching

---------

Co-authored-by: LLT21 <>
LLT21 10 months ago
parent
commit
d4b3ac8041

+ 7 - 9
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs

@@ -20,12 +20,6 @@ namespace appMpower.Orm.Data
          _dbConnection = dbConnection;
       }
 
-      public DbCommand(string commandText, DbConnection dbConnection, bool keyed)
-      {
-         _odbcCommand = dbConnection.GetCommand(commandText, CommandType.Text, keyed);
-         _dbConnection = dbConnection;
-      }
-
       public DbCommand(string commandText, CommandType commandType, DbConnection dbConnection)
       {
          _odbcCommand = dbConnection.GetCommand(commandText, commandType);
@@ -175,7 +169,7 @@ namespace appMpower.Orm.Data
 
       public async Task<int> ExecuteNonQueryAsync()
       {
-         return await (_odbcCommand as System.Data.Common.DbCommand).ExecuteNonQueryAsync();
+         return await _odbcCommand.ExecuteNonQueryAsync();
       }
 
       public IDataReader ExecuteReader(CommandBehavior behavior)
@@ -183,6 +177,11 @@ namespace appMpower.Orm.Data
          return _odbcCommand.ExecuteReader(behavior);
       }
 
+      public async Task<System.Data.Common.DbDataReader> ExecuteReaderAsync(CommandBehavior behavior)
+      {
+         return await _odbcCommand.ExecuteReaderAsync(behavior);
+      }
+
 #nullable enable
       public object? ExecuteScalar()
       {
@@ -197,8 +196,7 @@ namespace appMpower.Orm.Data
 
       public void Dispose()
       {
-         if (_dbConnection._keyed) _dbConnection._keyedOdbcCommands.TryAdd(_odbcCommand.CommandText, _odbcCommand);
-         else _dbConnection._odbcCommands.Push(_odbcCommand);
+         _dbConnection.Release(_odbcCommand);
       }
    }
 }

+ 54 - 33
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs

@@ -1,26 +1,27 @@
 using System.Collections.Concurrent;
 using System.Data;
-using System.Data.Odbc; 
+using System.Data.Odbc;
 
 namespace appMpower.Orm.Data
 {
    public class DbConnection : IDbConnection
    {
       private string _connectionString;
-      internal bool _keyed = false; 
-      internal int _number; 
-      internal OdbcConnection _odbcConnection;
-      internal ConcurrentStack<OdbcCommand> _odbcCommands = new();
-      internal Dictionary<string, OdbcCommand> _keyedOdbcCommands;
+      private bool _keyed = false;
+      private int _number;
+      private OdbcConnection _odbcConnection;
+      private ConcurrentStack<OdbcCommand> _odbcCommands = new();
+      private Dictionary<string, OdbcCommand> _keyedOdbcCommands;
 
       public DbConnection()
       {
-         _connectionString = DbProviderFactory.ConnectionString;
       }
 
-      public DbConnection(string connectionString)
+      public DbConnection(string connectionString, bool keyed = false)
       {
-         _connectionString = connectionString;
+         _keyed = keyed;
+         _connectionString = connectionString; 
+         GetConnection();
       }
 
       public IDbConnection Connection
@@ -43,7 +44,22 @@ namespace appMpower.Orm.Data
          }
          set
          {
-            _odbcConnection.ConnectionString = value;
+            _connectionString = value; 
+            GetConnection();
+         }
+      }
+
+      private void GetConnection()
+      {
+         if (_keyed)
+         {
+            (_number, _odbcConnection, _keyedOdbcCommands) = 
+               DbConnectionsKeyed.GetConnectionBase(_connectionString).GetAwaiter().GetResult();
+         }
+         else
+         {
+            (_number, _odbcConnection, _odbcCommands) = 
+               DbConnections.GetConnectionBase(_connectionString).GetAwaiter().GetResult();
          }
       }
 
@@ -99,23 +115,33 @@ namespace appMpower.Orm.Data
 
       public void Open()
       {
-         if (_odbcConnection is null)
+         if (_odbcConnection.State == ConnectionState.Closed)
          {
-            DbConnections.GetConnection(_connectionString, this);
+            _odbcConnection.Open();
          }
+      }
 
+      public async Task OpenAsync()
+      {
          if (_odbcConnection.State == ConnectionState.Closed)
          {
-            _odbcConnection.Open();
+            await _odbcConnection.OpenAsync();
          }
       }
 
       public void Dispose()
       {
-         DbConnections.Release(this);
+         if (_keyed)
+         {
+            DbConnectionsKeyed.Release((Number: _number, OdbcConnection: _odbcConnection, KeyedOdbcCommands: _keyedOdbcCommands));
+         }
+         else
+         {
+            DbConnections.Release((Number: _number, OdbcConnection: _odbcConnection, OdbcCommands: _odbcCommands));
+         }
       }
 
-      internal OdbcCommand GetCommand(string commandText, CommandType commandType, bool keyed = false)
+      internal OdbcCommand GetCommand(string commandText, CommandType commandType)
       {
          OdbcCommand odbcCommand;
 
@@ -129,25 +155,20 @@ namespace appMpower.Orm.Data
 
             return odbcCommand; 
          }
-         else if (_keyed && _keyedOdbcCommands.TryGetValue(commandText, out odbcCommand))
-         {
-            return odbcCommand; 
-         }
-         else
-         {
-            if (!_keyed && keyed) 
-            {
-               _keyedOdbcCommands = new();
-               _keyed = keyed; 
-            }
-            
-            odbcCommand = _odbcConnection.CreateCommand();
-            odbcCommand.CommandText = commandText;
-            odbcCommand.CommandType = commandType;
-            odbcCommand.Prepare();
+         else if (_keyed && _keyedOdbcCommands.TryGetValue(commandText, out odbcCommand)) return odbcCommand; 
 
-            return odbcCommand;
-         }
+         odbcCommand = _odbcConnection.CreateCommand();
+         odbcCommand.CommandText = commandText;
+         odbcCommand.CommandType = commandType;
+         odbcCommand.Prepare();
+
+         return odbcCommand;
+      }
+
+      internal void Release(OdbcCommand odbcCommand)
+      {
+         if (_keyed) _keyedOdbcCommands.TryAdd(odbcCommand.CommandText, odbcCommand);
+         else _odbcCommands.Push(odbcCommand);
       }
    }
 }

+ 32 - 32
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs

@@ -1,61 +1,61 @@
 using System.Collections.Concurrent;
+using System.Data.Odbc;
 
 namespace appMpower.Orm.Data
 {
-   public static class DbConnections
+   internal static class DbConnections
    {
+      private static bool _maxConnectionsCreated = false;
       private static short _createdConnections = 0;
-      private static ConcurrentStack<DbConnection> _connectionsStack = new();
+      private static short _maxConnections = 500;
 
-      public static DbConnection GetConnection(string connectionString)
+      private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> _connectionsStack = new();
+      private static ConcurrentQueue<TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)>> _waitingQueue = new();
+      
+      internal static async Task<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> GetConnectionBase(string connectionString)
       {
-         DbConnection popDbConnection; 
+         (int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands) dbConnectionBase;
 
-         if (!_connectionsStack.TryPop(out popDbConnection))
+         if (!_connectionsStack.TryPop(out dbConnectionBase))
          {
-            popDbConnection = new DbConnection();
-            popDbConnection._odbcConnection = new System.Data.Odbc.OdbcConnection(connectionString);
+            if (_maxConnectionsCreated)
+            {
+               dbConnectionBase = await GetDbConnectionBaseAsync();
+            }
+            else
+            {
+               _createdConnections++;
+               dbConnectionBase = (Number: _maxConnections, OdbcConnection: new OdbcConnection(connectionString), OdbcCommands: new ConcurrentStack<OdbcCommand>());
 
-            _createdConnections++;
-            popDbConnection._number = _createdConnections;
+               if (_createdConnections == _maxConnections) _maxConnectionsCreated = true;
 
-            if (_createdConnections % 25 == 0)
-            {
-               Console.WriteLine("Pooled connections created: " + _createdConnections.ToString());
+               //Console.WriteLine("opened connection number: " + dbConnectionBase._number);
             }
          }
 
-         return popDbConnection; 
+         return dbConnectionBase;
       }
 
-
-      public static void GetConnection(string connectionString, DbConnection dbConnection)
+      internal static void Release((int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands) dbConnectionBase)
       {
-         DbConnection popDbConnection = null;
+         TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> taskCompletionSource;
 
-         if (_connectionsStack.TryPop(out popDbConnection))
+         if (_waitingQueue.TryDequeue(out taskCompletionSource))
          {
-            dbConnection._odbcConnection = popDbConnection._odbcConnection; 
-            dbConnection._odbcCommands = popDbConnection._odbcCommands;
-            dbConnection._number = popDbConnection._number; 
+            taskCompletionSource.SetResult(dbConnectionBase);
          }
          else
          {
-            dbConnection._odbcConnection = new System.Data.Odbc.OdbcConnection(connectionString);
-
-            _createdConnections++;
-            dbConnection._number = _createdConnections;
-
-           if (_createdConnections % 25 == 0)
-            {
-               Console.WriteLine("Pooled connections created: " + _createdConnections.ToString());
-            }
-          }
+            _connectionsStack.Push(dbConnectionBase);
+         }
       }
 
-      public static void Release(DbConnection dbConnection)
+      private static Task<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)> GetDbConnectionBaseAsync()
       {
-         _connectionsStack.Push(dbConnection);
+         var taskCompletionSource = new TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, ConcurrentStack<OdbcCommand> OdbcCommands)>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+         _waitingQueue.Enqueue(taskCompletionSource);
+         return taskCompletionSource.Task;
       }
    }
 }

+ 61 - 0
frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs

@@ -0,0 +1,61 @@
+using System.Collections.Concurrent;
+using System.Data.Odbc;
+
+namespace appMpower.Orm.Data
+{
+   internal static class DbConnectionsKeyed
+   {
+      private static bool _maxConnectionsCreated = false;
+      private static short _createdConnections = 0;
+      private static short _maxConnections = 500;
+
+      private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)> _connectionsStack = new();
+      private static ConcurrentQueue<TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)>> _waitingQueue = new();
+
+      internal static async Task<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand> KeyedOdbcCommands)> GetConnectionBase(string connectionString)
+      {
+         (int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand> KeyedOdbcCommands) dbConnectionBase;
+
+         if (!_connectionsStack.TryPop(out dbConnectionBase))
+         {
+            if (_maxConnectionsCreated)
+            {
+               dbConnectionBase = await GetDbConnectionBaseAsync();
+            }
+            else
+            {
+               _createdConnections++;
+               dbConnectionBase = (Number: _maxConnections, OdbcConnection: new OdbcConnection(connectionString), KeyedOdbcCommands: new Dictionary<string, OdbcCommand>());
+
+               if (_createdConnections == _maxConnections) _maxConnectionsCreated = true;
+
+               //Console.WriteLine("opened connection number: " + dbConnectionBase._number);
+            }
+         }
+
+         return dbConnectionBase;
+      }
+
+      internal static void Release((int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand> KeyedOdbcCommands) dbConnectionBase)
+      {
+         TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)> taskCompletionSource;
+
+         if (_waitingQueue.TryDequeue(out taskCompletionSource))
+         {
+            taskCompletionSource.SetResult(dbConnectionBase);
+         }
+         else
+         {
+            _connectionsStack.Push(dbConnectionBase);
+         }
+      }
+
+      private static Task<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)> GetDbConnectionBaseAsync()
+      {
+         var taskCompletionSource = new TaskCompletionSource<(int Number, OdbcConnection OdbcConnection, Dictionary<string, OdbcCommand>)>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+         _waitingQueue.Enqueue(taskCompletionSource);
+         return taskCompletionSource.Task;
+      }
+   }
+}

+ 4 - 4
frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs

@@ -21,7 +21,7 @@ public static class DotnetMethods
 
     public static byte[] Db()
     {
-        var world = RawDb.LoadSingleQueryRow();
+        var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult();
 
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -33,7 +33,7 @@ public static class DotnetMethods
 
     public static byte[] Query(int queries)
     {
-        World[] worlds = RawDb.ReadMultipleRows(queries);
+        World[] worlds = RawDb.ReadMultipleRows(queries).GetAwaiter().GetResult();
 
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -45,7 +45,7 @@ public static class DotnetMethods
 
     public static byte[] Updates(int count)
     {
-        World[] worlds = RawDb.LoadMultipleUpdatesRows(count);
+        World[] worlds = RawDb.LoadMultipleUpdatesRows(count).GetAwaiter().GetResult();
 
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -57,7 +57,7 @@ public static class DotnetMethods
 
     public static byte[] Fortunes()
     {
-        List<Fortune> fortunes = RawDb.LoadFortunesRows(); 
+        List<Fortune> fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); 
         string fortunesView = FortunesView.Render(fortunes);
         byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView);
 

+ 5 - 5
frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs

@@ -42,7 +42,7 @@ public static class NativeMethods
     [UnmanagedCallersOnly(EntryPoint = "Db")]
     public static unsafe IntPtr Db(int* length, IntPtr* handlePointer)
     {
-        var world = RawDb.LoadSingleQueryRow();
+        var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult();
 
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -69,7 +69,7 @@ public static class NativeMethods
     [UnmanagedCallersOnly(EntryPoint = "Fortunes")]
     public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer)
     {
-        List<Fortune> fortunes = RawDb.LoadFortunesRows(); 
+        List<Fortune> fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); 
         string fortunesView = FortunesView.Render(fortunes);
         byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView);
 
@@ -85,7 +85,7 @@ public static class NativeMethods
     [UnmanagedCallersOnly(EntryPoint = "Query")]
     public static unsafe IntPtr Query(int queries, int* length, IntPtr* handlePointer)
     {
-        World[] worlds = RawDb.ReadMultipleRows(queries);
+        World[] worlds = RawDb.ReadMultipleRows(queries).GetAwaiter().GetResult();
 
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -105,7 +105,7 @@ public static class NativeMethods
     [UnmanagedCallersOnly(EntryPoint = "Updates")]
     public static unsafe IntPtr Updates(int count, int* length, IntPtr* handlePointer)
     {
-        World[] worlds = RawDb.LoadMultipleUpdatesRows(count);
+        World[] worlds = RawDb.LoadMultipleUpdatesRows(count).GetAwaiter().GetResult();
 
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);
@@ -125,7 +125,7 @@ public static class NativeMethods
     [UnmanagedCallersOnly(EntryPoint = "DbById")]
     public static unsafe IntPtr DbById(int id, int* length, IntPtr* handlePointer)
     {
-        var world = RawDb.LoadSingleQueryRowById(id);
+        var world = RawDb.LoadSingleQueryRowById(id).GetAwaiter().GetResult();
 
         var memoryStream = new MemoryStream();
         using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions);

+ 29 - 36
frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs

@@ -13,42 +13,42 @@ namespace appMpower.Orm
 
       private static string[] _queriesMultipleRows = new string[MaxBatch + 1];
 
-      public static World LoadSingleQueryRow()
+      public static async Task<World> LoadSingleQueryRow()
       {
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          var (dbCommand, _) = CreateReadCommand(pooledConnection);
 
          using (dbCommand)
          {
-            World world = ReadSingleRow(dbCommand);
+            World world = await ReadSingleRow(dbCommand);
 
             return world;
          }
       }
 
-      public static World LoadSingleQueryRowById(int id)
+      public static async Task<World> LoadSingleQueryRowById(int id)
       {
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          var (dbCommand, _) = CreateReadCommandById(pooledConnection, id);
 
          using (dbCommand)
          {
-            World world = ReadSingleRow(dbCommand);
+            World world = await ReadSingleRow(dbCommand);
 
             return world;
          }
       }
 
-      public static World[] LoadMultipleQueriesRows(int count)
+      public static async Task<World[]> LoadMultipleQueriesRows(int count)
       {
          var worlds = new World[count];
 
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection);
 
@@ -56,7 +56,7 @@ namespace appMpower.Orm
          {
             for (int i = 0; i < count; i++)
             {
-               worlds[i] = ReadSingleRow(dbCommand);
+               worlds[i] = await ReadSingleRow(dbCommand);
                dbDataParameter.Value = _random.Next(1, 10001);
             }
          }
@@ -64,18 +64,18 @@ namespace appMpower.Orm
          return worlds;
       }
 
-      public static List<Fortune> LoadFortunesRows()
+      public static async Task<List<Fortune>> LoadFortunesRows()
       {
          var fortunes = new List<Fortune>();
 
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          var dbCommand = new DbCommand("SELECT * FROM fortune", pooledConnection);
 
          using (dbCommand)
          {
-            IDataReader dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess);
+            IDataReader dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess);
 
             while (dataReader.Read())
             {
@@ -97,25 +97,25 @@ namespace appMpower.Orm
          return fortunes;
       }
 
-      public static World[] LoadMultipleUpdatesRows(int count)
+      public static async Task<World[]> LoadMultipleUpdatesRows(int count)
       {
          var worlds = new World[count];
 
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString, true);
+         await pooledConnection.OpenAsync();
 
-         var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection, true);
+         var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection);
 
          using (queryCommand)
          {
             for (int i = 0; i < count; i++)
             {
-               worlds[i] = ReadSingleRow(queryCommand);
+               worlds[i] = await ReadSingleRow(queryCommand);
                dbDataParameter.Value = _random.Next(1, 10001);
             }
          }
 
-         using var updateCommand = new DbCommand(BatchUpdateString.Query(count), pooledConnection, true);
+         using var updateCommand = new DbCommand(BatchUpdateString.Query(count), pooledConnection);
 
          var ids = BatchUpdateString.Ids;
          var randoms = BatchUpdateString.Randoms;
@@ -152,13 +152,6 @@ namespace appMpower.Orm
          return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001)));
       }
 
-      internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommand(DbConnection pooledConnection, bool keyed)
-      {
-         DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection, keyed);
-
-         return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, _random.Next(1, 10001)));
-      }
-
       internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommandById(DbConnection pooledConnection, int id)
       {
          DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection);
@@ -166,9 +159,9 @@ namespace appMpower.Orm
          return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, id));
       }
 
-      internal static World ReadSingleRow(DbCommand dbCommand)
+      internal static async Task<World> ReadSingleRow(DbCommand dbCommand)
       {
-         var dataReader = dbCommand.ExecuteReader(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess);
+         var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess);
 
          dataReader.Read();
 
@@ -183,7 +176,7 @@ namespace appMpower.Orm
          return world;
       }
 
-      public static World[] ReadMultipleRows(int count)
+      public static async Task<World[]> ReadMultipleRows(int count)
       {
          int j = 0;
          var ids = BatchUpdateString.Ids;
@@ -206,8 +199,8 @@ namespace appMpower.Orm
             queryString = _queriesMultipleRows[count] = StringBuilderCache.GetStringAndRelease(stringBuilder);
          }
 
-         using var pooledConnection = DbConnections.GetConnection(DbProviderFactory.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          using var dbCommand = new DbCommand(queryString, pooledConnection);
 
@@ -216,7 +209,7 @@ namespace appMpower.Orm
             dbCommand.CreateParameter(ids[i], DbType.Int32, _random.Next(1, 10001));
          }
 
-         var dataReader = dbCommand.ExecuteReader(CommandBehavior.Default & CommandBehavior.SequentialAccess);
+         var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.Default & CommandBehavior.SequentialAccess);
 
          do
          {
@@ -229,7 +222,7 @@ namespace appMpower.Orm
             };
 
             j++;
-         } while (dataReader.NextResult());
+         } while (await dataReader.NextResultAsync());
 
          dataReader.Close();