Skip to content

DbBatchBatcher throws InvalidOperationException on empty batch execution #3725

@ja-kar

Description

@ja-kar

Description

DbBatchBatcher (available in NHibernate 5.6.0) throws InvalidOperationException when attempting to execute an empty
batch, while other batchers (GenericBatchingBatcher and SqlClientBatchingBatcher) handle this scenario correctly.

Error

System.InvalidOperationException: ExecuteNonQuery: CommandText property has not been initialized
at Microsoft.Data.SqlClient.SqlCommand.ValidateCommand(Boolean isAsync, String method)
at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean
sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName)
at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Microsoft.Data.SqlClient.SqlBatch.ExecuteNonQuery()
at NHibernate.AdoNet.DbBatchBatcher.DoExecuteBatch(DbCommand ps)

Root Cause

DbBatchBatcher.DoExecuteBatch() and DoExecuteBatchAsync() lack empty batch validation that exists in other
batchers. When ExecuteBatch() is called with an empty batch (_currentBatch.BatchCommands.Count == 0), the code
attempts to execute a DbBatch with no commands, causing the CommandText to be uninitialized.

File: src/NHibernate/AdoNet/DbBatchBatcher.cs
Methods: DoExecuteBatch() (line 116) and DoExecuteBatchAsync() (line 145)

Comparison with Other Batchers

GenericBatchingBatcher (working correctly):

protected override void DoExecuteBatch(DbCommand ps)
{
    if (_currentBatch.CountOfCommands == 0)
    {
        Expectations.VerifyOutcomeBatched(_totalExpectedRowsAffected, 0, ps);
        return;
    }
    // ... proceed with execution
}

DbBatchBatcher (missing check):

protected override void DoExecuteBatch(DbCommand ps)
{
    try
    {
        // Missing empty batch check here
        rowsAffected = _currentBatch.ExecuteNonQuery(); // Throws on empty batch

Proposed Fix

Add empty batch check at the beginning of both methods:

protected override void DoExecuteBatch(DbCommand ps)
{
    if (_currentBatch.BatchCommands.Count == 0)
    {
        Expectations.VerifyOutcomeBatched(_totalExpectedRowsAffected, 0, ps);
        return;
    }
    // ... existing code
}

Environment

  • NHibernate version: 5.6.0
  • .NET version: 8
  • Database: SQL Server

Impact

This causes runtime exceptions in scenarios where ExecuteBatch() is triggered without any commands being added to
the batch, which can occur during normal session lifecycle operations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions