Search code examples
c#hibernatenhibernatefluent-nhibernate

Can send batch insert but not update queries to DB


I can successfully send batch insert requests to the DB, but not updates. I have tried different approaches, but nothing seems to issue the batch updates.

I could not find a solution for this issue. Some examples I've tried (not all):

*Important. I must not use stateless sessions.

Here is a unit test I use to test this case:

[Test]
public void Test_BatchUpdateTest()
{
    // Arrange
    const int batchSize = 2;

    var dto1Oid = Guid.Empty;
    var dto2Oid = Guid.Empty;

    // Generates a transaction, executes the content, and commit it afterwards. 
    // Batch inserts are correct, both are sent with no extra roundtrips to DB.
    businessObject.Transact(() => {
        var dto1 = new DtoType {ArchivingDate = DateTime.Now.AddDays(-7)};
        var dto2 = new DtoType {ArchivingDate = DateTime.Now};
        businessObject.Save(dto1); // Calls Session.SaveOrUpdate
        businessObject.Save(dto2); // Calls Session.SaveOrUpdate

        dto1Oid = dto1.Oid ?? Guid.Empty;
        dto2Oid = dto2.Oid ?? Guid.Empty;
    }, batchSize); // Calls Session.SetBatchSize(batchSize); before executing content above, sets it back to default after commit

    // Act
    businessObject.Transact(() =>
    {
        var dto1 = businessObject.LoadObject(dto1Oid);
        var dto2 = businessObject.LoadObject(dto2Oid);

        // Changing data to generate Update requests (should be sent in batches)
        dto1.ArchivingDate = DateTime.Now.AddDays(7);
        dto2.ArchivingDate = DateTime.Now.AddDays(1);

        businessObject.Save(dto1);
        businessObject.Save(dto2);
    }, batchSize); // Calls Session.SetBatchSize(batchSize); before executing content above, sets it back to default after commit

    // Assert
    //<Check DB Requests on NHibernate Profiler> // On NHProfiler, the inserts are sent in a single request as seen in "Insert request"
}

Insert request (batch correctly sent):

INSERT INTO DtoType
            (... Fields)
VALUES      (... Values)

--//////////////////////////////////////////////////

INSERT INTO DtoType
            (... Fields)
VALUES      (... Values)

Update Request 1 (first update, should be in batch with request 2 below):

UPDATE DtoType
SET    ArchivingDate = '<updated date>'
WHERE  Id = '<dto1 id>'

Update request 2 (second update, should be in batch with request 1 above):

UPDATE DtoType
SET    ArchivingDate = '<updated date>'
WHERE  Id = '<dto2 id>'

My goal is to send only 1 request for both updates, like in the insert request.


Solution

  • The problem was that I used NHibernate v4 and the data structure DtoType uses versioning. Batch updating versioned structures isn't supported in NH v4.The support was added in v5 (link here) Using v5 and adding the nhibernate setting adonet.batch_versioned_data=true solved my issue. I can now send batch update requests to the DB.