Skip to content

Commit 87b8d9c

Browse files
Maksim Sustretovhazzik
Maksim Sustretov
authored andcommitted
NH-3912 - Batch operations with the same IBatcher instance fail on expected rows count after single failed operation.
1 parent 28a0a39 commit 87b8d9c

File tree

4 files changed

+138
-10
lines changed

4 files changed

+138
-10
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.NH3912
4+
{
5+
class BatcherLovingEntity
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
}
10+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
using System;
2+
using System.Linq;
3+
using NHibernate.AdoNet;
4+
using NHibernate.Cfg;
5+
using NHibernate.Cfg.MappingSchema;
6+
using NHibernate.Driver;
7+
using NHibernate.Engine;
8+
using NHibernate.Linq;
9+
using NHibernate.Mapping.ByCode;
10+
using NUnit.Framework;
11+
12+
namespace NHibernate.Test.NHSpecificTest.NH3912
13+
{
14+
public class ReusableBatcherFixture : TestCaseMappingByCode
15+
{
16+
protected override bool AppliesTo(ISessionFactoryImplementor factory)
17+
{
18+
var driver = factory.ConnectionProvider.Driver;
19+
return driver is OracleDataClientDriver ||
20+
driver is OracleLiteDataClientDriver ||
21+
driver is OracleManagedDataClientDriver;
22+
}
23+
24+
protected override HbmMapping GetMappings()
25+
{
26+
var mapper = new ModelMapper();
27+
mapper.Class<BatcherLovingEntity>(rc =>
28+
{
29+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
30+
rc.Property(x => x.Name, m => m.Unique(true));
31+
});
32+
33+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
34+
}
35+
36+
protected override void Configure(Configuration configuration)
37+
{
38+
base.Configure(configuration);
39+
configuration.SetProperty(Cfg.Environment.BatchStrategy,
40+
typeof(OracleDataClientBatchingBatcherFactory).AssemblyQualifiedName);
41+
}
42+
43+
protected override void OnSetUp()
44+
{
45+
using (var session = OpenSession())
46+
using (var transaction = session.BeginTransaction())
47+
{
48+
var e1 = new BatcherLovingEntity { Name = "Bob" };
49+
session.Save(e1);
50+
51+
var e2 = new BatcherLovingEntity { Name = "Sally" };
52+
session.Save(e2);
53+
54+
session.Flush();
55+
transaction.Commit();
56+
}
57+
}
58+
59+
protected override void OnTearDown()
60+
{
61+
using (var session = OpenSession())
62+
using (var transaction = session.BeginTransaction())
63+
{
64+
session.Delete("from System.Object");
65+
66+
session.Flush();
67+
transaction.Commit();
68+
}
69+
}
70+
71+
/// <summary> Batch operations with the same IBatcher instance fail on expect rows count after single failed operation. </summary>
72+
[Test]
73+
public void Test_Batcher_Is_Reusable_After_Failed_Operation()
74+
{
75+
using (var session = OpenSession())
76+
{
77+
try
78+
{
79+
using (session.BeginTransaction())
80+
{
81+
var valid = new BatcherLovingEntity { Name = "Bill" };
82+
session.Save(valid);
83+
84+
Assert.That(() => session.Query<BatcherLovingEntity>().Count(x => x.Name == "Bob"), Is.EqualTo(1));
85+
var bob = new BatcherLovingEntity { Name = "Bob" };
86+
session.Save(bob);
87+
88+
// Should fail on unique constraint violation
89+
// Expected behavior
90+
session.Flush();
91+
}
92+
}
93+
catch (Exception)
94+
{
95+
// Opening next transaction in the same session after rollback
96+
// to log the problem, for instance.
97+
// Executing in the same session with the same instance of IBatcher
98+
using (session.BeginTransaction())
99+
{
100+
// Inserting any valid entity will fail on expected rows count assert in batcher
101+
var e1 = new BatcherLovingEntity { Name = "Robert (because Bob already exists)" };
102+
session.Save(e1);
103+
// Batch update returned unexpected row count from update; actual row count: 1; expected: 2
104+
session.Flush();
105+
}
106+
}
107+
}
108+
}
109+
}
110+
}

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,8 @@
733733
<Compile Include="NHSpecificTest\EntityWithUserTypeCanHaveLinqGenerators\IExample.cs" />
734734
<Compile Include="NHSpecificTest\NH2204\Model.cs" />
735735
<Compile Include="NHSpecificTest\NH2204\Fixture.cs" />
736+
<Compile Include="NHSpecificTest\NH3912\BatcherLovingEntity.cs" />
737+
<Compile Include="NHSpecificTest\NH3912\ReusableBatcherFixture.cs" />
736738
<Compile Include="NHSpecificTest\NH3414\Entity.cs" />
737739
<Compile Include="NHSpecificTest\NH3414\FixtureByCode.cs" />
738740
<Compile Include="NHSpecificTest\NH2218\Fixture.cs" />

src/NHibernate/AdoNet/OracleDataClientBatchingBatcher.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,21 +125,27 @@ protected override void DoExecuteBatch(IDbCommand ps)
125125
// this value is not a part of the ADO.NET API.
126126
// It's and ODP implementation, so it is being set by reflection
127127
SetArrayBindCount(arraySize);
128-
int rowsAffected;
129128
try
130129
{
131-
rowsAffected = _currentBatch.ExecuteNonQuery();
130+
int rowsAffected;
131+
try
132+
{
133+
rowsAffected = _currentBatch.ExecuteNonQuery();
134+
}
135+
catch (DbException e)
136+
{
137+
throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, string.Format("could not execute batch command."));
138+
}
139+
140+
Expectations.VerifyOutcomeBatched(_totalExpectedRowsAffected, rowsAffected);
132141
}
133-
catch (DbException e)
142+
finally
134143
{
135-
throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "could not execute batch command.");
144+
// Cleaning up even if batched outcome is invalid
145+
_totalExpectedRowsAffected = 0;
146+
_currentBatch = null;
147+
_parameterValueListHashTable = null;
136148
}
137-
138-
Expectations.VerifyOutcomeBatched(_totalExpectedRowsAffected, rowsAffected);
139-
140-
_totalExpectedRowsAffected = 0;
141-
_currentBatch = null;
142-
_parameterValueListHashTable = null;
143149
}
144150
}
145151

0 commit comments

Comments
 (0)