schotime / NPoco

Simple microORM that maps the results of a query onto a POCO object. Project based on Schotime's branch of PetaPoco
Apache License 2.0
847 stars 301 forks source link

NullReferenceException / InvalidOperationException on multiple calls to Async Db method #698

Open jennablackwell opened 7 months ago

jennablackwell commented 7 months ago

I understand that NPoco autocloses it's db connection unless specifying a shared connection. However, I noticed in several of my projects if a call to the database happens too fast consecutively (such as doing an insert into a Log table), a "NullReferenceException" is thrown because it's saying the connection is null. I've tried manually adding checks to make sure the connection is explicitly set and that doesn't seem to help either. I've tried initializing a new NPoco instance to use for the db call, but that doesn't seem to help either. Not sure there is something else going on deeper in the library code.

Db call example - this throws the exception: await Db.InsertAsync(myObject); *Note: When hovering over the "Db" object in debug, it is not null and no "myObject" is not null either. It will work the first time executing this code but subsequent executions if too fast will throw the exception.

Exception example: System.NullReferenceException HResult=0x80004003 Message=Object reference not set to an instance of an object. Source=NPoco StackTrace: at NPoco.Database.CloseSharedConnection() at NPoco.Database.d__3`1.MoveNext()

Usually I get a NullReferenceException but I've also gotten other errors such as "Connection is closed" etc. Here's below examples:

System.InvalidOperationException: Invalid operation. The connection is closed. at Microsoft.Data.SqlClient.SqlConnection.GetOpenTdsConnection() at Microsoft.Data.SqlClient.SqlCommand.WaitForAsyncResults(IAsyncResult asyncResult, Boolean isInternal) at Microsoft.Data.SqlClient.SqlCommand.InternalEndExecuteReader(IAsyncResult asyncResult, Boolean isInternal, String endMethod) at Microsoft.Data.SqlClient.SqlCommand.EndExecuteReaderInternal(IAsyncResult asyncResult) at Microsoft.Data.SqlClient.SqlCommand.EndExecuteReaderAsync(IAsyncResult asyncResult) at System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 promise, Boolean requiresSynchronization) --- End of stack trace from previous location --- at NPoco.Database.ExecutionHookAsync[T](Func`1 action) at NPoco.Database.ExecuteScalarHelperAsync(DbCommand cmd) at NPoco.Database.InsertAsyncImp[T](PocoData pocoData, String tableName, String primaryKeyName, Boolean autoIncrement, T poco, Boolean sync)

System.InvalidOperationException: BeginExecuteReader requires an open and available Connection. The connection's current state is open. at Microsoft.Data.SqlClient.SqlConnection.GetOpenTdsConnection(String method) at Microsoft.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command) at Microsoft.Data.SqlClient.SqlCommand.ValidateCommand(Boolean isAsync, String method) at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method) at Microsoft.Data.SqlClient.SqlCommand.BeginExecuteReaderInternal(CommandBehavior behavior, AsyncCallback callback, Object stateObject, Int32 timeout, Boolean inRetry, Boolean asyncWrite) at Microsoft.Data.SqlClient.SqlCommand.BeginExecuteReaderAsyncCallback(AsyncCallback callback, Object stateObject) at System.Threading.Tasks.TaskFactory1.FromAsyncImpl(Func3 beginMethod, Func2 endFunction, Action1 endAction, Object state, TaskCreationOptions creationOptions) at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) --- End of stack trace from previous location --- at NPoco.Database.ExecutionHookAsync[T](Func1 action) at NPoco.Database.ExecuteScalarHelperAsync(DbCommand cmd) at NPoco.Database.InsertAsyncImp[T](PocoData pocoData, String tableName, String primaryKeyName, Boolean autoIncrement, T poco, Boolean sync)

schotime commented 7 months ago

The only way CloseSharedConnection() null references is if you are using the same IDatabase instance across multiple threads.

jennablackwell commented 7 months ago

The only way CloseSharedConnection() null references is if you are using the same IDatabase instance across multiple threads.

Hmm.. I did try also doing something like this for my queries, but it seemed to still throw the same errors... i'll try it out once more tho.

using (IDatabase db = new Database("connStringName")) { List users = db.Fetch("select userId, email from users"); }