|
1 | 1 | using System;
|
2 |
| -using System.Collections; |
3 | 2 | using System.Linq;
|
4 |
| -using System.Reflection; |
5 | 3 | using System.Threading;
|
6 | 4 | using System.Transactions;
|
7 | 5 | using log4net;
|
8 | 6 | using log4net.Repository.Hierarchy;
|
9 |
| -using NHibernate.Cfg; |
10 |
| -using NHibernate.Cfg.MappingSchema; |
11 | 7 | using NHibernate.Linq;
|
12 |
| -using NHibernate.Tool.hbm2ddl; |
13 | 8 | using NUnit.Framework;
|
14 | 9 |
|
15 |
| -namespace NHibernate.Test.NHSpecificTest.DtcFailures |
| 10 | +namespace NHibernate.Test.SystemTransactions |
16 | 11 | {
|
17 | 12 | [TestFixture]
|
18 |
| - public class DtcFailuresFixture : TestCase |
| 13 | + public class DistributedTransactionFixture : TransactionFixtureBase |
19 | 14 | {
|
20 |
| - private static readonly ILog _log = LogManager.GetLogger(typeof(DtcFailuresFixture)); |
21 |
| - |
22 |
| - protected override IList Mappings |
23 |
| - => new[] { "NHSpecificTest.DtcFailures.Mappings.hbm.xml" }; |
24 |
| - |
25 |
| - protected override string MappingsAssembly |
26 |
| - => "NHibernate.Test"; |
| 15 | + private static readonly ILog _log = LogManager.GetLogger(typeof(DistributedTransactionFixture)); |
27 | 16 |
|
28 | 17 | protected override bool AppliesTo(Dialect.Dialect dialect)
|
29 | 18 | => dialect.SupportsDistributedTransactions;
|
30 | 19 |
|
31 |
| - protected override void CreateSchema() |
32 |
| - { |
33 |
| - // Copied from Configure method. |
34 |
| - var config = new Configuration(); |
35 |
| - if (TestConfigurationHelper.hibernateConfigFile != null) |
36 |
| - config.Configure(TestConfigurationHelper.hibernateConfigFile); |
37 |
| - |
38 |
| - // Our override so we can set nullability on database column without NHibernate knowing about it. |
39 |
| - config.BeforeBindMapping += BeforeBindMapping; |
40 |
| - |
41 |
| - // Copied from AddMappings methods. |
42 |
| - var assembly = Assembly.Load(MappingsAssembly); |
43 |
| - foreach (var file in Mappings) |
44 |
| - config.AddResource(MappingsAssembly + "." + file, assembly); |
45 |
| - |
46 |
| - // Copied from CreateSchema method, but we use our own config. |
47 |
| - new SchemaExport(config).Create(false, true); |
48 |
| - } |
49 |
| - |
50 |
| - protected override void OnTearDown() |
51 |
| - { |
52 |
| - DodgeTransactionCompletionDelayIfRequired(); |
53 |
| - |
54 |
| - using (var s = OpenSession()) |
55 |
| - using (var t = s.BeginTransaction()) |
56 |
| - { |
57 |
| - s.CreateQuery("delete from System.Object").ExecuteUpdate(); |
58 |
| - t.Commit(); |
59 |
| - } |
60 |
| - } |
61 |
| - |
62 |
| - private void BeforeBindMapping(object sender, BindMappingEventArgs e) |
63 |
| - { |
64 |
| - var prop = e.Mapping.RootClasses[0].Properties.OfType<HbmProperty>().Single(p => p.Name == "NotNullData"); |
65 |
| - prop.notnull = true; |
66 |
| - prop.notnullSpecified = true; |
67 |
| - } |
68 |
| - |
69 | 20 | [Test]
|
70 | 21 | public void SupportsEnlistingInDistributed()
|
71 | 22 | {
|
@@ -108,7 +59,7 @@ public void SupportsPromotingToDistributed()
|
108 | 59 | }
|
109 | 60 |
|
110 | 61 | [Test]
|
111 |
| - public void WillNotCrashOnDtcPrepareFailure() |
| 62 | + public void WillNotCrashOnPrepareFailure() |
112 | 63 | {
|
113 | 64 | var tx = new TransactionScope();
|
114 | 65 | var disposeCalled = false;
|
@@ -484,6 +435,74 @@ public void NH1744()
|
484 | 435 | }
|
485 | 436 | }
|
486 | 437 |
|
| 438 | + [Test] |
| 439 | + public void CanUseSessionWithManyScopes([Values(false, true)] bool explicitFlush) |
| 440 | + { |
| 441 | + // Note that this fails with ConnectionReleaseMode.OnClose and SqlServer: |
| 442 | + // System.Data.SqlClient.SqlException : Microsoft Distributed Transaction Coordinator (MS DTC) has stopped this transaction. |
| 443 | + using (var s = OpenSession()) |
| 444 | + //using (var s = Sfi.WithOptions().ConnectionReleaseMode(ConnectionReleaseMode.OnClose).OpenSession()) |
| 445 | + { |
| 446 | + using (var tx = new TransactionScope()) |
| 447 | + { |
| 448 | + ForceEscalationToDistributedTx.Escalate(); |
| 449 | + // Acquire the connection |
| 450 | + var count = s.Query<Person>().Count(); |
| 451 | + Assert.That(count, Is.EqualTo(0), "Unexpected initial entity count."); |
| 452 | + tx.Complete(); |
| 453 | + } |
| 454 | + // No dodge here please! Allow to check chaining usages do not fail. |
| 455 | + using (var tx = new TransactionScope()) |
| 456 | + { |
| 457 | + s.Save(new Person { CreatedAt = DateTime.Today }); |
| 458 | + |
| 459 | + ForceEscalationToDistributedTx.Escalate(); |
| 460 | + |
| 461 | + if (explicitFlush) |
| 462 | + s.Flush(); |
| 463 | + |
| 464 | + tx.Complete(); |
| 465 | + } |
| 466 | + |
| 467 | + DodgeTransactionCompletionDelayIfRequired(); |
| 468 | + |
| 469 | + using (var tx = new TransactionScope()) |
| 470 | + { |
| 471 | + ForceEscalationToDistributedTx.Escalate(); |
| 472 | + var count = s.Query<Person>().Count(); |
| 473 | + Assert.That(count, Is.EqualTo(1), "Unexpected entity count after committed insert."); |
| 474 | + tx.Complete(); |
| 475 | + } |
| 476 | + using (new TransactionScope()) |
| 477 | + { |
| 478 | + s.Save(new Person { CreatedAt = DateTime.Today }); |
| 479 | + |
| 480 | + ForceEscalationToDistributedTx.Escalate(); |
| 481 | + |
| 482 | + if (explicitFlush) |
| 483 | + s.Flush(); |
| 484 | + |
| 485 | + // No complete for rollback-ing. |
| 486 | + } |
| 487 | + |
| 488 | + DodgeTransactionCompletionDelayIfRequired(); |
| 489 | + |
| 490 | + // Do not reuse the session after a rollback, its state does not allow it. |
| 491 | + // http://nhibernate.info/doc/nhibernate-reference/manipulatingdata.html#manipulatingdata-endingsession-commit |
| 492 | + } |
| 493 | + |
| 494 | + using (var s = OpenSession()) |
| 495 | + { |
| 496 | + using (var tx = new TransactionScope()) |
| 497 | + { |
| 498 | + ForceEscalationToDistributedTx.Escalate(); |
| 499 | + var count = s.Query<Person>().Count(); |
| 500 | + Assert.That(count, Is.EqualTo(1), "Unexpected entity count after rollback-ed insert."); |
| 501 | + tx.Complete(); |
| 502 | + } |
| 503 | + } |
| 504 | + } |
| 505 | + |
487 | 506 | [Test]
|
488 | 507 | public void CanUseSessionOutsideOfScopeAfterScope([Values(false, true)] bool explicitFlush)
|
489 | 508 | {
|
@@ -551,15 +570,6 @@ public void DelayedTransactionCompletion([Values(false, true)] bool explicitFlus
|
551 | 570 | }
|
552 | 571 | }
|
553 | 572 |
|
554 |
| - private void AssertNoPersons() |
555 |
| - { |
556 |
| - using (var s = OpenSession()) |
557 |
| - using (s.BeginTransaction()) |
558 |
| - { |
559 |
| - Assert.AreEqual(0, s.Query<Person>().Count(), "Entities found in database."); |
560 |
| - } |
561 |
| - } |
562 |
| - |
563 | 573 | private void DodgeTransactionCompletionDelayIfRequired()
|
564 | 574 | {
|
565 | 575 | if (Sfi.ConnectionProvider.Driver.HasDelayedDistributedTransactionCompletion)
|
|
0 commit comments