Skip to content

Commit cd2e8ea

Browse files
Fix implied commits for Oracle and MySQL (#3485)
1 parent 2742b57 commit cd2e8ea

File tree

9 files changed

+233
-21
lines changed

9 files changed

+233
-21
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System.Linq;
12+
using NUnit.Framework;
13+
using NHibernate.Linq;
14+
15+
namespace NHibernate.Test.NHSpecificTest.GH3474
16+
{
17+
using System.Threading.Tasks;
18+
[TestFixture]
19+
public class FixtureAsync : BugTestCase
20+
{
21+
protected override void OnSetUp()
22+
{
23+
using var session = OpenSession();
24+
using var transaction = session.BeginTransaction();
25+
26+
var e1 = new CreditCardPayment { CreditCardType = "Visa", Amount = 50 };
27+
session.Save(e1);
28+
29+
var e2 = new ChequePayment { Bank = "CA", Amount = 32 };
30+
session.Save(e2);
31+
32+
var e3 = new CashPayment { Amount = 18.5m };
33+
session.Save(e3);
34+
35+
transaction.Commit();
36+
}
37+
38+
protected override void OnTearDown()
39+
{
40+
using var session = OpenSession();
41+
using var transaction = session.BeginTransaction();
42+
43+
// The HQL delete does all the job inside the database without loading the entities, but it does
44+
// not handle delete order for avoiding violating constraints if any. Use
45+
// session.Delete("from System.Object");
46+
// instead if in need of having NHibernate ordering the deletes, but this will cause
47+
// loading the entities in the session.
48+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
49+
50+
transaction.Commit();
51+
}
52+
53+
[Test]
54+
public async Task PolymorphicUpdateShouldNotCommitAsync()
55+
{
56+
using (var session = OpenSession())
57+
using (var transaction = session.BeginTransaction())
58+
{
59+
var payment = await (session.Query<CreditCardPayment>().FirstAsync());
60+
payment.Amount = 100;
61+
await (session.FlushAsync());
62+
63+
await (session.CreateQuery("update ChequePayment set Amount = 64").ExecuteUpdateAsync());
64+
65+
await (transaction.RollbackAsync());
66+
}
67+
68+
using (var session = OpenSession())
69+
using (var transaction = session.BeginTransaction())
70+
{
71+
IPayment payment = await (session.Query<CreditCardPayment>().FirstAsync());
72+
Assert.That(payment.Amount, Is.EqualTo(50m));
73+
74+
payment = await (session.Query<ChequePayment>().FirstAsync());
75+
Assert.That(payment.Amount, Is.EqualTo(32m));
76+
77+
await (transaction.CommitAsync());
78+
}
79+
}
80+
}
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH3474
4+
{
5+
public interface IPayment
6+
{
7+
public Guid Id { get; set; }
8+
public decimal Amount { get; set; }
9+
}
10+
11+
public class CreditCardPayment : IPayment
12+
{
13+
public virtual Guid Id { get; set; }
14+
public virtual decimal Amount { get; set; }
15+
public virtual string CreditCardType { get; set; }
16+
}
17+
18+
public class CashPayment : IPayment
19+
{
20+
public virtual Guid Id { get; set; }
21+
public virtual decimal Amount { get; set; }
22+
}
23+
24+
public class ChequePayment : IPayment
25+
{
26+
public virtual Guid Id { get; set; }
27+
public virtual decimal Amount { get; set; }
28+
public virtual string Bank { get; set; }
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System.Linq;
2+
using NUnit.Framework;
3+
4+
namespace NHibernate.Test.NHSpecificTest.GH3474
5+
{
6+
[TestFixture]
7+
public class Fixture : BugTestCase
8+
{
9+
protected override void OnSetUp()
10+
{
11+
using var session = OpenSession();
12+
using var transaction = session.BeginTransaction();
13+
14+
var e1 = new CreditCardPayment { CreditCardType = "Visa", Amount = 50 };
15+
session.Save(e1);
16+
17+
var e2 = new ChequePayment { Bank = "CA", Amount = 32 };
18+
session.Save(e2);
19+
20+
var e3 = new CashPayment { Amount = 18.5m };
21+
session.Save(e3);
22+
23+
transaction.Commit();
24+
}
25+
26+
protected override void OnTearDown()
27+
{
28+
using var session = OpenSession();
29+
using var transaction = session.BeginTransaction();
30+
31+
// The HQL delete does all the job inside the database without loading the entities, but it does
32+
// not handle delete order for avoiding violating constraints if any. Use
33+
// session.Delete("from System.Object");
34+
// instead if in need of having NHibernate ordering the deletes, but this will cause
35+
// loading the entities in the session.
36+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
37+
38+
transaction.Commit();
39+
}
40+
41+
[Test]
42+
public void PolymorphicUpdateShouldNotCommit()
43+
{
44+
using (var session = OpenSession())
45+
using (var transaction = session.BeginTransaction())
46+
{
47+
var payment = session.Query<CreditCardPayment>().First();
48+
payment.Amount = 100;
49+
session.Flush();
50+
51+
session.CreateQuery("update ChequePayment set Amount = 64").ExecuteUpdate();
52+
53+
transaction.Rollback();
54+
}
55+
56+
using (var session = OpenSession())
57+
using (var transaction = session.BeginTransaction())
58+
{
59+
IPayment payment = session.Query<CreditCardPayment>().First();
60+
Assert.That(payment.Amount, Is.EqualTo(50m));
61+
62+
payment = session.Query<ChequePayment>().First();
63+
Assert.That(payment.Amount, Is.EqualTo(32m));
64+
65+
transaction.Commit();
66+
}
67+
}
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test"
3+
namespace="NHibernate.Test.NHSpecificTest.GH3474">
4+
5+
<class name="IPayment" table="Payment">
6+
<id name="Id" generator="guid.comb" />
7+
<property name="Amount" />
8+
<joined-subclass name="CreditCardPayment">
9+
<key column="Id" />
10+
<property name="CreditCardType" />
11+
</joined-subclass>
12+
<joined-subclass name="CashPayment">
13+
<key column="Id"/>
14+
</joined-subclass>
15+
<joined-subclass name="ChequePayment">
16+
<key column="Id"/>
17+
<property name="Bank" />
18+
</joined-subclass>
19+
</class>
20+
21+
</hibernate-mapping>

src/NHibernate/Async/Hql/Ast/ANTLR/Exec/AbstractStatementExecutor.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public async Task DoWorkAsync(DbConnection connection, DbTransaction transaction
162162
{
163163
stmnt = connection.CreateCommand();
164164
stmnt.Transaction = transaction;
165-
stmnt.CommandText = "drop table " + persister.TemporaryIdTableName;
165+
stmnt.CommandText = $"{session.Factory.Dialect.DropTemporaryTableString} {persister.TemporaryIdTableName}";
166166
await (stmnt.ExecuteNonQueryAsync(cancellationToken)).ConfigureAwait(false);
167167
session.Factory.Settings.SqlStatementLogger.LogCommand(stmnt, FormatStyle.Ddl);
168168
}

src/NHibernate/Dialect/Dialect.cs

+22-19
Original file line numberDiff line numberDiff line change
@@ -717,28 +717,28 @@ public virtual string GenerateTemporaryTableName(string baseTableName)
717717

718718
/// <summary>
719719
/// Does the dialect require that temporary table DDL statements occur in
720-
/// isolation from other statements? This would be the case if the creation
720+
/// isolation from other statements? This would be the case if the creation
721721
/// would cause any current transaction to get committed implicitly.
722-
/// </summary>
723-
/// <returns> see the result matrix above. </returns>
722+
/// </summary>
723+
/// <returns>See the result matrix in the remarks.</returns>
724724
/// <remarks>
725-
/// JDBC defines a standard way to query for this information via the
726-
/// {@link java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()}
727-
/// method. However, that does not distinguish between temporary table
728-
/// DDL and other forms of DDL; MySQL, for example, reports DDL causing a
729-
/// transaction commit via its driver, even though that is not the case for
730-
/// temporary table DDL.
731-
/// <p/>
732-
/// Possible return values and their meanings:<ul>
733-
/// <li>{@link Boolean#TRUE} - Unequivocally, perform the temporary table DDL in isolation.</li>
734-
/// <li>{@link Boolean#FALSE} - Unequivocally, do <b>not</b> perform the temporary table DDL in isolation.</li>
735-
/// <li><i>null</i> - defer to the JDBC driver response in regards to {@link java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()}</li>
736-
/// </ul>
725+
/// Possible return values and their meanings:
726+
/// <list type="bullet">
727+
/// <item>
728+
/// <term><see langword="true" /></term>
729+
/// <description>Unequivocally, perform the temporary table DDL in isolation.</description>
730+
/// </item>
731+
/// <item>
732+
/// <term><see langword="false" /></term>
733+
/// <description>Unequivocally, do <b>not</b> perform the temporary table DDL in isolation.</description>
734+
/// </item>
735+
/// <item>
736+
/// <term><see langword="null" /></term>
737+
/// <description>Defer to <see cref="Cfg.Settings.IsDataDefinitionImplicitCommit" />.</description>
738+
/// </item>
739+
/// </list>
737740
/// </remarks>
738-
public virtual bool? PerformTemporaryTableDDLInIsolation()
739-
{
740-
return null;
741-
}
741+
public virtual bool? PerformTemporaryTableDDLInIsolation() => null;
742742

743743
/// <summary> Do we need to drop the temporary table after use? </summary>
744744
public virtual bool DropTemporaryTableAfterUse()
@@ -2471,6 +2471,9 @@ public virtual string CreateTemporaryTableString
24712471
get { return "create table"; }
24722472
}
24732473

2474+
/// <summary>Command used to drop a temporary table.</summary>
2475+
public virtual string DropTemporaryTableString => "drop table";
2476+
24742477
/// <summary>
24752478
/// Get any fragments needing to be postfixed to the command for
24762479
/// temporary table creation.

src/NHibernate/Dialect/MySQLDialect.cs

+3
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,9 @@ public override string CreateTemporaryTableString
451451
get { return "create temporary table if not exists"; }
452452
}
453453

454+
/// <inheritdoc />
455+
public override string DropTemporaryTableString => "drop temporary table";
456+
454457
protected virtual void RegisterCastTypes()
455458
{
456459
// According to the MySql documentation (http://dev.mysql.com/doc/refman/4.1/en/cast-functions.html)

src/NHibernate/Dialect/Oracle8iDialect.cs

+5
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,11 @@ public override string GenerateTemporaryTableName(String baseTableName)
532532
return name.Length > 30 ? name.Substring(1, (30) - (1)) : name;
533533
}
534534

535+
/// <inheritdoc />
536+
/// <remarks>Oracle does commit any pending transaction prior to executing any DDL,
537+
/// included for temporary tables.</remarks>
538+
public override bool? PerformTemporaryTableDDLInIsolation() => true;
539+
535540
public override bool DropTemporaryTableAfterUse()
536541
{
537542
return false;

src/NHibernate/Hql/Ast/ANTLR/Exec/AbstractStatementExecutor.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ public void DoWork(DbConnection connection, DbTransaction transaction)
298298
{
299299
stmnt = connection.CreateCommand();
300300
stmnt.Transaction = transaction;
301-
stmnt.CommandText = "drop table " + persister.TemporaryIdTableName;
301+
stmnt.CommandText = $"{session.Factory.Dialect.DropTemporaryTableString} {persister.TemporaryIdTableName}";
302302
stmnt.ExecuteNonQuery();
303303
session.Factory.Settings.SqlStatementLogger.LogCommand(stmnt, FormatStyle.Ddl);
304304
}

0 commit comments

Comments
 (0)