diff --git a/src/AsyncGenerator.yml b/src/AsyncGenerator.yml
index 7b8a269d01c..3c541dc7315 100644
--- a/src/AsyncGenerator.yml
+++ b/src/AsyncGenerator.yml
@@ -170,6 +170,8 @@
applyChanges: true
analyzation:
methodConversion:
+ - conversion: Copy
+ name: AfterTransactionCompletionProcess_EvictsFromCache
- conversion: Copy
hasAttributeName: OneTimeSetUpAttribute
- conversion: Copy
diff --git a/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs b/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs
new file mode 100644
index 00000000000..4361dbefa5a
--- /dev/null
+++ b/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by AsyncGenerator.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+
+using System;
+using System.Collections;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using NHibernate.Cache;
+using NHibernate.Cfg;
+using NSubstitute;
+using NUnit.Framework;
+using Environment = NHibernate.Cfg.Environment;
+
+namespace NHibernate.Test.BulkManipulation
+{
+ using System.Threading.Tasks;
+ [TestFixture]
+ public class NativeSQLBulkOperationsWithCacheAsync : TestCase
+ {
+ protected override string MappingsAssembly => "NHibernate.Test";
+
+ protected override IList Mappings => new[] { "BulkManipulation.Vehicle.hbm.xml" };
+
+ protected override void Configure(Configuration configuration)
+ {
+ cfg.SetProperty(Environment.UseQueryCache, "true");
+ cfg.SetProperty(Environment.UseSecondLevelCache, "true");
+ cfg.SetProperty(Environment.CacheProvider, typeof(SubstituteCacheProvider).AssemblyQualifiedName);
+ }
+
+ [Test]
+ public async Task SimpleNativeSQLInsert_DoesNotEvictEntireCacheWhenQuerySpacesAreAddedAsync()
+ {
+ List clearCalls = new List();
+ (Sfi.Settings.CacheProvider as SubstituteCacheProvider).OnClear(x =>
+ {
+ clearCalls.Add(x);
+ });
+ using (var s = OpenSession())
+ {
+ string ssql = "UPDATE Vehicle SET Vin='123' WHERE Vin='123c'";
+
+ using (var t = s.BeginTransaction())
+ {
+
+ await (s.CreateSQLQuery(ssql).ExecuteUpdateAsync());
+ await (t.CommitAsync());
+
+ Assert.AreEqual(1, clearCalls.Count);
+ }
+
+ clearCalls.Clear();
+
+ using (var t = s.BeginTransaction())
+ {
+ await (s.CreateSQLQuery(ssql).AddSynchronizedQuerySpace("Unknown").ExecuteUpdateAsync());
+ await (t.CommitAsync());
+
+ Assert.AreEqual(0, clearCalls.Count);
+ }
+ }
+ }
+ }
+}
diff --git a/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs b/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs
index 3a69352f4f8..4b3d76497da 100644
--- a/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs
+++ b/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs
@@ -54,7 +54,7 @@ public class GeneralTestAsync : TestCase
protected override IList Mappings
{
- get { return new[] { "SqlTest.Query.NativeSQLQueries.hbm.xml" }; }
+ get { return new[] {"SqlTest.Query.NativeSQLQueries.hbm.xml"}; }
}
protected override string MappingsAssembly
@@ -103,17 +103,17 @@ public async Task SQLQueryInterfaceAsync()
await (s.SaveAsync(emp));
IList l = await (s.CreateSQLQuery(OrgEmpRegionSQL)
- .AddEntity("org", typeof(Organization))
- .AddJoin("emp", "org.employments")
- .AddScalar("regionCode", NHibernateUtil.String)
- .ListAsync());
+ .AddEntity("org", typeof(Organization))
+ .AddJoin("emp", "org.employments")
+ .AddScalar("regionCode", NHibernateUtil.String)
+ .ListAsync());
Assert.AreEqual(2, l.Count);
l = await (s.CreateSQLQuery(OrgEmpPersonSQL)
- .AddEntity("org", typeof(Organization))
- .AddJoin("emp", "org.employments")
- .AddJoin("pers", "emp.employee")
- .ListAsync());
+ .AddEntity("org", typeof(Organization))
+ .AddJoin("emp", "org.employments")
+ .AddJoin("pers", "emp.employee")
+ .ListAsync());
Assert.AreEqual(l.Count, 1);
await (t.CommitAsync());
@@ -122,13 +122,14 @@ public async Task SQLQueryInterfaceAsync()
s = OpenSession();
t = s.BeginTransaction();
- l = await (s.CreateSQLQuery("select {org.*}, {emp.*} " +
- "from ORGANIZATION org " +
- " left outer join EMPLOYMENT emp on org.ORGID = emp.EMPLOYER, ORGANIZATION org2")
- .AddEntity("org", typeof(Organization))
- .AddJoin("emp", "org.employments")
- .SetResultTransformer(new DistinctRootEntityResultTransformer())
- .ListAsync());
+ l = await (s.CreateSQLQuery(
+ "select {org.*}, {emp.*} " +
+ "from ORGANIZATION org " +
+ " left outer join EMPLOYMENT emp on org.ORGID = emp.EMPLOYER, ORGANIZATION org2")
+ .AddEntity("org", typeof(Organization))
+ .AddJoin("emp", "org.employments")
+ .SetResultTransformer(new DistinctRootEntityResultTransformer())
+ .ListAsync());
Assert.AreEqual(l.Count, 2);
await (t.CommitAsync());
@@ -162,13 +163,13 @@ public async Task ResultSetMappingDefinitionAsync()
await (s.SaveAsync(emp));
IList l = await (s.CreateSQLQuery(OrgEmpRegionSQL)
- .SetResultSetMapping("org-emp-regionCode")
- .ListAsync());
+ .SetResultSetMapping("org-emp-regionCode")
+ .ListAsync());
Assert.AreEqual(l.Count, 2);
l = await (s.CreateSQLQuery(OrgEmpPersonSQL)
- .SetResultSetMapping("org-emp-person")
- .ListAsync());
+ .SetResultSetMapping("org-emp-person")
+ .ListAsync());
Assert.AreEqual(l.Count, 1);
await (s.DeleteAsync(emp));
@@ -313,7 +314,7 @@ public async Task MappedAliasStrategyAsync()
sqlQuery.SetResultTransformer(CriteriaSpecification.AliasToEntityMap);
list = await (sqlQuery.ListAsync());
Assert.AreEqual(2, list.Count);
- m = (IDictionary)list[0];
+ m = (IDictionary) list[0];
Assert.IsTrue(m.Contains("org"));
AssertClassAssignability(m["org"].GetType(), typeof(Organization));
Assert.IsTrue(m.Contains("emp"));
@@ -381,28 +382,29 @@ public async Task CompositeIdJoinsFailureExpectedAsync()
s = OpenSession();
t = s.BeginTransaction();
- object[] o = (object[]) (await (s.CreateSQLQuery("select\r\n" +
- " product.orgid as {product.id.orgid}," +
- " product.productnumber as {product.id.productnumber}," +
- " {prod_orders}.orgid as orgid3_1_,\r\n" +
- " {prod_orders}.ordernumber as ordernum2_3_1_,\r\n" +
- " product.name as {product.name}," +
- " {prod_orders.element.*}," +
- /*" orders.PROD_NO as PROD4_3_1_,\r\n" +
- " orders.person as person3_1_,\r\n" +
- " orders.PROD_ORGID as PROD3_0__,\r\n" +
- " orders.PROD_NO as PROD4_0__,\r\n" +
- " orders.orgid as orgid0__,\r\n" +
- " orders.ordernumber as ordernum2_0__ \r\n" +*/
- " from\r\n" +
- " Product product \r\n" +
- " inner join\r\n" +
- " TBL_ORDER {prod_orders} \r\n" +
- " on product.orgid={prod_orders}.PROD_ORGID \r\n" +
- " and product.productnumber={prod_orders}.PROD_NO")
- .AddEntity("product", typeof(Product))
- .AddJoin("prod_orders", "product.orders")
- .ListAsync()))[0];
+ object[] o = (object[]) (await (s.CreateSQLQuery(
+ "select\r\n" +
+ " product.orgid as {product.id.orgid}," +
+ " product.productnumber as {product.id.productnumber}," +
+ " {prod_orders}.orgid as orgid3_1_,\r\n" +
+ " {prod_orders}.ordernumber as ordernum2_3_1_,\r\n" +
+ " product.name as {product.name}," +
+ " {prod_orders.element.*}," +
+ /*" orders.PROD_NO as PROD4_3_1_,\r\n" +
+ " orders.person as person3_1_,\r\n" +
+ " orders.PROD_ORGID as PROD3_0__,\r\n" +
+ " orders.PROD_NO as PROD4_0__,\r\n" +
+ " orders.orgid as orgid0__,\r\n" +
+ " orders.ordernumber as ordernum2_0__ \r\n" +*/
+ " from\r\n" +
+ " Product product \r\n" +
+ " inner join\r\n" +
+ " TBL_ORDER {prod_orders} \r\n" +
+ " on product.orgid={prod_orders}.PROD_ORGID \r\n" +
+ " and product.productnumber={prod_orders}.PROD_NO")
+ .AddEntity("product", typeof(Product))
+ .AddJoin("prod_orders", "product.orders")
+ .ListAsync()))[0];
p = (Product) o[0];
Assert.IsTrue(NHibernateUtil.IsInitialized(p.Orders));
@@ -432,8 +434,8 @@ public async Task AutoDetectAliasingAsync()
s = OpenSession();
t = s.BeginTransaction();
IList list = await (s.CreateSQLQuery(EmploymentSQL)
- .AddEntity(typeof(Employment).FullName)
- .ListAsync());
+ .AddEntity(typeof(Employment).FullName)
+ .ListAsync());
Assert.AreEqual(1, list.Count);
Employment emp2 = (Employment) list[0];
@@ -444,9 +446,9 @@ public async Task AutoDetectAliasingAsync()
s.Clear();
list = await (s.CreateSQLQuery(EmploymentSQL)
- .AddEntity(typeof(Employment).FullName)
- .SetResultTransformer(CriteriaSpecification.AliasToEntityMap)
- .ListAsync());
+ .AddEntity(typeof(Employment).FullName)
+ .SetResultTransformer(CriteriaSpecification.AliasToEntityMap)
+ .ListAsync());
Assert.AreEqual(1, list.Count);
IDictionary m = (IDictionary) list[0];
Assert.IsTrue(m.Contains("Employment"));
@@ -485,17 +487,17 @@ public async Task AutoDetectAliasingAsync()
s.Clear();
list = await (s.CreateSQLQuery(OrganizationJoinEmploymentSQL)
- .AddEntity("org", typeof(Organization))
- .AddJoin("emp", "org.employments")
- .ListAsync());
+ .AddEntity("org", typeof(Organization))
+ .AddJoin("emp", "org.employments")
+ .ListAsync());
Assert.AreEqual(2, list.Count);
s.Clear();
list = await (s.CreateSQLQuery(OrganizationFetchJoinEmploymentSQL)
- .AddEntity("org", typeof(Organization))
- .AddJoin("emp", "org.employments")
- .ListAsync());
+ .AddEntity("org", typeof(Organization))
+ .AddJoin("emp", "org.employments")
+ .ListAsync());
Assert.AreEqual(2, list.Count);
s.Clear();
@@ -569,8 +571,8 @@ public async Task MixAndMatchEntityScalarAsync()
s.Clear();
IList l = await (s.CreateSQLQuery("select name, id, flength, name as scalarName from Speech")
- .SetResultSetMapping("speech")
- .ListAsync());
+ .SetResultSetMapping("speech")
+ .ListAsync());
Assert.AreEqual(l.Count, 1);
await (t.RollbackAsync());
@@ -583,9 +585,9 @@ public async Task ParameterListAsync()
using (ISession s = OpenSession())
{
IList l = await (s.CreateSQLQuery("select id from Speech where id in (:idList)")
- .AddScalar("id", NHibernateUtil.Int32)
- .SetParameterList("idList", new int[] {0, 1, 2, 3}, NHibernateUtil.Int32)
- .ListAsync());
+ .AddScalar("id", NHibernateUtil.Int32)
+ .SetParameterList("idList", new int[] {0, 1, 2, 3}, NHibernateUtil.Int32)
+ .ListAsync());
}
}
@@ -607,23 +609,26 @@ private double ExtractDoubleValue(object value)
public static void AssertClassAssignability(System.Type source, System.Type target)
{
- Assert.IsTrue(target.IsAssignableFrom(source),
- "Classes were not assignment-compatible : source<" +
- source.FullName +
- "> target<" +
- target.FullName + ">"
- );
+ Assert.IsTrue(
+ target.IsAssignableFrom(source),
+ "Classes were not assignment-compatible : source<" +
+ source.FullName +
+ "> target<" +
+ target.FullName + ">"
+ );
}
class TestResultSetTransformer : IResultTransformer
{
public bool TransformTupleCalled { get; set; }
public bool TransformListCalled { get; set; }
+
public object TransformTuple(object[] tuple, string[] aliases)
{
this.TransformTupleCalled = true;
return tuple;
}
+
public IList TransformList(IList collection)
{
this.TransformListCalled = true;
@@ -716,5 +721,33 @@ public async Task CanExecuteFutureValueAsync()
Assert.AreEqual("Ricardo", v);
}
}
+
+ [Test]
+ public async Task HandlesManualSynchronizationAsync()
+ {
+ using (var s = OpenSession())
+ using (s.BeginTransaction())
+ {
+ s.SessionFactory.Statistics.IsStatisticsEnabled = true;
+ s.SessionFactory.Statistics.Clear();
+
+ // create an Organization...
+ Organization jboss = new Organization("JBoss");
+ await (s.PersistAsync(jboss));
+
+ // now query on Employment, this should not cause an auto-flush
+ await (s.CreateSQLQuery(EmploymentSQL).AddSynchronizedQuerySpace("ABC").ListAsync());
+ Assert.AreEqual(0, s.SessionFactory.Statistics.EntityInsertCount);
+
+ // now try to query on Employment but this time add Organization as a synchronized query space...
+ await (s.CreateSQLQuery(EmploymentSQL).AddSynchronizedEntityClass(typeof(Organization)).ListAsync());
+ Assert.AreEqual(1, s.SessionFactory.Statistics.EntityInsertCount);
+
+ // clean up
+ await (s.DeleteAsync(jboss));
+ await (s.Transaction.CommitAsync());
+ s.Close();
+ }
+ }
}
}
diff --git a/src/NHibernate.Test/BulkManipulation/BulkOperationCleanupActionFixture.cs b/src/NHibernate.Test/BulkManipulation/BulkOperationCleanupActionFixture.cs
new file mode 100644
index 00000000000..53a099c753f
--- /dev/null
+++ b/src/NHibernate.Test/BulkManipulation/BulkOperationCleanupActionFixture.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NHibernate.Action;
+using NHibernate.Engine;
+using NHibernate.Metadata;
+using NHibernate.Persister.Entity;
+using NSubstitute;
+using NUnit.Framework;
+
+namespace NHibernate.Test.BulkManipulation
+{
+ [TestFixture]
+ public class BulkOperationCleanupActionFixture
+ {
+ private ISessionImplementor _session;
+ private ISessionFactoryImplementor _factory;
+ private IEntityPersister _persister;
+
+ [SetUp]
+ public void SetupTest()
+ {
+ _session = Substitute.For();
+ _factory = Substitute.For();
+ _persister = Substitute.For();
+ _session.Factory.Returns(_factory);
+ _factory.GetAllClassMetadata().Returns(new Dictionary { ["TestClass"] = null });
+ _factory.GetEntityPersister("TestClass").Returns(_persister);
+ _factory.GetCollectionRolesByEntityParticipant("TestClass").Returns(new HashSet(new[] { "TestClass.Children" }));
+ _persister.QuerySpaces.Returns(new[] { "TestClass" });
+ _persister.EntityName.Returns("TestClass");
+ }
+
+ [TestCase("TestClass", true, 1, 1, 1)]
+ [TestCase("AnotherClass", true, 1, 0, 0)]
+ [TestCase("AnotherClass,TestClass", true, 2, 1, 1)]
+ [TestCase("TestClass", false, 1, 0, 1)]
+ [TestCase("", true, 1, 1, 1)]
+ [Test]
+ // 6.0 TODO: remove this ignore.
+ [Ignore("Must wait for the tested methods to be actually added to ISessionFactoryImplementor")]
+ public void AfterTransactionCompletionProcess_EvictsFromCache(string querySpaces, bool persisterHasCache, int expectedPropertySpaceLength, int expectedEntityEvictionCount, int expectedCollectionEvictionCount)
+ {
+ _persister.HasCache.Returns(persisterHasCache);
+
+ var target = new BulkOperationCleanupAction(_session, new HashSet(querySpaces.Split(new []{','},StringSplitOptions.RemoveEmptyEntries)));
+
+ target.AfterTransactionCompletionProcess(true);
+
+ Assert.AreEqual(expectedPropertySpaceLength, target.PropertySpaces.Length);
+
+ if (expectedEntityEvictionCount > 0)
+ {
+ _factory.Received(1).EvictEntity(Arg.Is>(x => x.Count() == expectedEntityEvictionCount));
+ }
+ else
+ {
+ _factory.DidNotReceive().EvictEntity(Arg.Any>());
+ }
+
+ if (expectedCollectionEvictionCount > 0)
+ {
+ _factory.Received(1).EvictCollection(Arg.Is>(x => x.Count() == expectedCollectionEvictionCount));
+ }
+ else
+ {
+ _factory.DidNotReceive().EvictCollection(Arg.Any>());
+ }
+ }
+ }
+}
diff --git a/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs b/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs
new file mode 100644
index 00000000000..54b19b970aa
--- /dev/null
+++ b/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using NHibernate.Cache;
+using NHibernate.Cfg;
+using NSubstitute;
+using NUnit.Framework;
+using Environment = NHibernate.Cfg.Environment;
+
+namespace NHibernate.Test.BulkManipulation
+{
+ [TestFixture]
+ public class NativeSQLBulkOperationsWithCache : TestCase
+ {
+ protected override string MappingsAssembly => "NHibernate.Test";
+
+ protected override IList Mappings => new[] { "BulkManipulation.Vehicle.hbm.xml" };
+
+ protected override void Configure(Configuration configuration)
+ {
+ cfg.SetProperty(Environment.UseQueryCache, "true");
+ cfg.SetProperty(Environment.UseSecondLevelCache, "true");
+ cfg.SetProperty(Environment.CacheProvider, typeof(SubstituteCacheProvider).AssemblyQualifiedName);
+ }
+
+ [Test]
+ public void SimpleNativeSQLInsert_DoesNotEvictEntireCacheWhenQuerySpacesAreAdded()
+ {
+ List clearCalls = new List();
+ (Sfi.Settings.CacheProvider as SubstituteCacheProvider).OnClear(x =>
+ {
+ clearCalls.Add(x);
+ });
+ using (var s = OpenSession())
+ {
+ string ssql = "UPDATE Vehicle SET Vin='123' WHERE Vin='123c'";
+
+ using (var t = s.BeginTransaction())
+ {
+
+ s.CreateSQLQuery(ssql).ExecuteUpdate();
+ t.Commit();
+
+ Assert.AreEqual(1, clearCalls.Count);
+ }
+
+ clearCalls.Clear();
+
+ using (var t = s.BeginTransaction())
+ {
+ s.CreateSQLQuery(ssql).AddSynchronizedQuerySpace("Unknown").ExecuteUpdate();
+ t.Commit();
+
+ Assert.AreEqual(0, clearCalls.Count);
+ }
+ }
+ }
+ }
+
+ public class SubstituteCacheProvider : ICacheProvider
+ {
+ private readonly ConcurrentDictionary> _caches = new ConcurrentDictionary>();
+ private Action _onClear;
+
+ public ICache BuildCache(string regionName, IDictionary properties)
+ {
+ return _caches.GetOrAdd(regionName, x => new Lazy(() =>
+ {
+ var cache = Substitute.For();
+ cache.RegionName.Returns(regionName);
+ cache.When(c => c.Clear()).Do(c => _onClear?.Invoke(regionName));
+ return cache;
+ })).Value;
+ }
+
+ public long NextTimestamp()
+ {
+ return Timestamper.Next();
+ }
+
+ public void Start(IDictionary properties)
+ {
+ }
+
+ public void Stop()
+ {
+ }
+
+ public ICache GetCache(string region)
+ {
+ Lazy cache;
+ _caches.TryGetValue(region, out cache);
+ return cache?.Value;
+ }
+
+ public IEnumerable GetAllCaches()
+ {
+ return _caches.Values.Select(x => x.Value);
+ }
+
+ public void OnClear(Action callback)
+ {
+ _onClear = callback;
+ }
+ }
+}
diff --git a/src/NHibernate.Test/MappingByCode/For.cs b/src/NHibernate.Test/MappingByCode/For.cs
index 46f76f8b05b..1ab97920ec0 100644
--- a/src/NHibernate.Test/MappingByCode/For.cs
+++ b/src/NHibernate.Test/MappingByCode/For.cs
@@ -16,4 +16,4 @@ public static MemberInfo Property(Expression> propertyGetter)
return TypeExtensions.DecodeMemberAccessExpression(propertyGetter);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj
index 3ae3f734cda..6e6df5e293d 100644
--- a/src/NHibernate.Test/NHibernate.Test.csproj
+++ b/src/NHibernate.Test/NHibernate.Test.csproj
@@ -49,7 +49,7 @@
-
+
diff --git a/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs b/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs
index 69cc26b6ee3..f655d771cb9 100644
--- a/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs
+++ b/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs
@@ -43,7 +43,7 @@ public class GeneralTest : TestCase
protected override IList Mappings
{
- get { return new[] { "SqlTest.Query.NativeSQLQueries.hbm.xml" }; }
+ get { return new[] {"SqlTest.Query.NativeSQLQueries.hbm.xml"}; }
}
protected override string MappingsAssembly
@@ -92,17 +92,17 @@ public void SQLQueryInterface()
s.Save(emp);
IList l = s.CreateSQLQuery(OrgEmpRegionSQL)
- .AddEntity("org", typeof(Organization))
- .AddJoin("emp", "org.employments")
- .AddScalar("regionCode", NHibernateUtil.String)
- .List();
+ .AddEntity("org", typeof(Organization))
+ .AddJoin("emp", "org.employments")
+ .AddScalar("regionCode", NHibernateUtil.String)
+ .List();
Assert.AreEqual(2, l.Count);
l = s.CreateSQLQuery(OrgEmpPersonSQL)
- .AddEntity("org", typeof(Organization))
- .AddJoin("emp", "org.employments")
- .AddJoin("pers", "emp.employee")
- .List();
+ .AddEntity("org", typeof(Organization))
+ .AddJoin("emp", "org.employments")
+ .AddJoin("pers", "emp.employee")
+ .List();
Assert.AreEqual(l.Count, 1);
t.Commit();
@@ -111,13 +111,14 @@ public void SQLQueryInterface()
s = OpenSession();
t = s.BeginTransaction();
- l = s.CreateSQLQuery("select {org.*}, {emp.*} " +
- "from ORGANIZATION org " +
- " left outer join EMPLOYMENT emp on org.ORGID = emp.EMPLOYER, ORGANIZATION org2")
- .AddEntity("org", typeof(Organization))
- .AddJoin("emp", "org.employments")
- .SetResultTransformer(new DistinctRootEntityResultTransformer())
- .List();
+ l = s.CreateSQLQuery(
+ "select {org.*}, {emp.*} " +
+ "from ORGANIZATION org " +
+ " left outer join EMPLOYMENT emp on org.ORGID = emp.EMPLOYER, ORGANIZATION org2")
+ .AddEntity("org", typeof(Organization))
+ .AddJoin("emp", "org.employments")
+ .SetResultTransformer(new DistinctRootEntityResultTransformer())
+ .List();
Assert.AreEqual(l.Count, 2);
t.Commit();
@@ -151,13 +152,13 @@ public void ResultSetMappingDefinition()
s.Save(emp);
IList l = s.CreateSQLQuery(OrgEmpRegionSQL)
- .SetResultSetMapping("org-emp-regionCode")
- .List();
+ .SetResultSetMapping("org-emp-regionCode")
+ .List();
Assert.AreEqual(l.Count, 2);
l = s.CreateSQLQuery(OrgEmpPersonSQL)
- .SetResultSetMapping("org-emp-person")
- .List();
+ .SetResultSetMapping("org-emp-person")
+ .List();
Assert.AreEqual(l.Count, 1);
s.Delete(emp);
@@ -302,7 +303,7 @@ public void MappedAliasStrategy()
sqlQuery.SetResultTransformer(CriteriaSpecification.AliasToEntityMap);
list = sqlQuery.List();
Assert.AreEqual(2, list.Count);
- m = (IDictionary)list[0];
+ m = (IDictionary) list[0];
Assert.IsTrue(m.Contains("org"));
AssertClassAssignability(m["org"].GetType(), typeof(Organization));
Assert.IsTrue(m.Contains("emp"));
@@ -370,28 +371,29 @@ public void CompositeIdJoinsFailureExpected()
s = OpenSession();
t = s.BeginTransaction();
- object[] o = (object[]) s.CreateSQLQuery("select\r\n" +
- " product.orgid as {product.id.orgid}," +
- " product.productnumber as {product.id.productnumber}," +
- " {prod_orders}.orgid as orgid3_1_,\r\n" +
- " {prod_orders}.ordernumber as ordernum2_3_1_,\r\n" +
- " product.name as {product.name}," +
- " {prod_orders.element.*}," +
- /*" orders.PROD_NO as PROD4_3_1_,\r\n" +
- " orders.person as person3_1_,\r\n" +
- " orders.PROD_ORGID as PROD3_0__,\r\n" +
- " orders.PROD_NO as PROD4_0__,\r\n" +
- " orders.orgid as orgid0__,\r\n" +
- " orders.ordernumber as ordernum2_0__ \r\n" +*/
- " from\r\n" +
- " Product product \r\n" +
- " inner join\r\n" +
- " TBL_ORDER {prod_orders} \r\n" +
- " on product.orgid={prod_orders}.PROD_ORGID \r\n" +
- " and product.productnumber={prod_orders}.PROD_NO")
- .AddEntity("product", typeof(Product))
- .AddJoin("prod_orders", "product.orders")
- .List()[0];
+ object[] o = (object[]) s.CreateSQLQuery(
+ "select\r\n" +
+ " product.orgid as {product.id.orgid}," +
+ " product.productnumber as {product.id.productnumber}," +
+ " {prod_orders}.orgid as orgid3_1_,\r\n" +
+ " {prod_orders}.ordernumber as ordernum2_3_1_,\r\n" +
+ " product.name as {product.name}," +
+ " {prod_orders.element.*}," +
+ /*" orders.PROD_NO as PROD4_3_1_,\r\n" +
+ " orders.person as person3_1_,\r\n" +
+ " orders.PROD_ORGID as PROD3_0__,\r\n" +
+ " orders.PROD_NO as PROD4_0__,\r\n" +
+ " orders.orgid as orgid0__,\r\n" +
+ " orders.ordernumber as ordernum2_0__ \r\n" +*/
+ " from\r\n" +
+ " Product product \r\n" +
+ " inner join\r\n" +
+ " TBL_ORDER {prod_orders} \r\n" +
+ " on product.orgid={prod_orders}.PROD_ORGID \r\n" +
+ " and product.productnumber={prod_orders}.PROD_NO")
+ .AddEntity("product", typeof(Product))
+ .AddJoin("prod_orders", "product.orders")
+ .List()[0];
p = (Product) o[0];
Assert.IsTrue(NHibernateUtil.IsInitialized(p.Orders));
@@ -421,8 +423,8 @@ public void AutoDetectAliasing()
s = OpenSession();
t = s.BeginTransaction();
IList list = s.CreateSQLQuery(EmploymentSQL)
- .AddEntity(typeof(Employment).FullName)
- .List();
+ .AddEntity(typeof(Employment).FullName)
+ .List();
Assert.AreEqual(1, list.Count);
Employment emp2 = (Employment) list[0];
@@ -433,9 +435,9 @@ public void AutoDetectAliasing()
s.Clear();
list = s.CreateSQLQuery(EmploymentSQL)
- .AddEntity(typeof(Employment).FullName)
- .SetResultTransformer(CriteriaSpecification.AliasToEntityMap)
- .List();
+ .AddEntity(typeof(Employment).FullName)
+ .SetResultTransformer(CriteriaSpecification.AliasToEntityMap)
+ .List();
Assert.AreEqual(1, list.Count);
IDictionary m = (IDictionary) list[0];
Assert.IsTrue(m.Contains("Employment"));
@@ -474,17 +476,17 @@ public void AutoDetectAliasing()
s.Clear();
list = s.CreateSQLQuery(OrganizationJoinEmploymentSQL)
- .AddEntity("org", typeof(Organization))
- .AddJoin("emp", "org.employments")
- .List();
+ .AddEntity("org", typeof(Organization))
+ .AddJoin("emp", "org.employments")
+ .List();
Assert.AreEqual(2, list.Count);
s.Clear();
list = s.CreateSQLQuery(OrganizationFetchJoinEmploymentSQL)
- .AddEntity("org", typeof(Organization))
- .AddJoin("emp", "org.employments")
- .List();
+ .AddEntity("org", typeof(Organization))
+ .AddJoin("emp", "org.employments")
+ .List();
Assert.AreEqual(2, list.Count);
s.Clear();
@@ -558,8 +560,8 @@ public void MixAndMatchEntityScalar()
s.Clear();
IList l = s.CreateSQLQuery("select name, id, flength, name as scalarName from Speech")
- .SetResultSetMapping("speech")
- .List();
+ .SetResultSetMapping("speech")
+ .List();
Assert.AreEqual(l.Count, 1);
t.Rollback();
@@ -572,9 +574,9 @@ public void ParameterList()
using (ISession s = OpenSession())
{
IList l = s.CreateSQLQuery("select id from Speech where id in (:idList)")
- .AddScalar("id", NHibernateUtil.Int32)
- .SetParameterList("idList", new int[] {0, 1, 2, 3}, NHibernateUtil.Int32)
- .List();
+ .AddScalar("id", NHibernateUtil.Int32)
+ .SetParameterList("idList", new int[] {0, 1, 2, 3}, NHibernateUtil.Int32)
+ .List();
}
}
@@ -596,23 +598,26 @@ private double ExtractDoubleValue(object value)
public static void AssertClassAssignability(System.Type source, System.Type target)
{
- Assert.IsTrue(target.IsAssignableFrom(source),
- "Classes were not assignment-compatible : source<" +
- source.FullName +
- "> target<" +
- target.FullName + ">"
- );
+ Assert.IsTrue(
+ target.IsAssignableFrom(source),
+ "Classes were not assignment-compatible : source<" +
+ source.FullName +
+ "> target<" +
+ target.FullName + ">"
+ );
}
class TestResultSetTransformer : IResultTransformer
{
public bool TransformTupleCalled { get; set; }
public bool TransformListCalled { get; set; }
+
public object TransformTuple(object[] tuple, string[] aliases)
{
this.TransformTupleCalled = true;
return tuple;
}
+
public IList TransformList(IList collection)
{
this.TransformListCalled = true;
@@ -705,5 +710,33 @@ public void CanExecuteFutureValue()
Assert.AreEqual("Ricardo", v);
}
}
+
+ [Test]
+ public void HandlesManualSynchronization()
+ {
+ using (var s = OpenSession())
+ using (s.BeginTransaction())
+ {
+ s.SessionFactory.Statistics.IsStatisticsEnabled = true;
+ s.SessionFactory.Statistics.Clear();
+
+ // create an Organization...
+ Organization jboss = new Organization("JBoss");
+ s.Persist(jboss);
+
+ // now query on Employment, this should not cause an auto-flush
+ s.CreateSQLQuery(EmploymentSQL).AddSynchronizedQuerySpace("ABC").List();
+ Assert.AreEqual(0, s.SessionFactory.Statistics.EntityInsertCount);
+
+ // now try to query on Employment but this time add Organization as a synchronized query space...
+ s.CreateSQLQuery(EmploymentSQL).AddSynchronizedEntityClass(typeof(Organization)).List();
+ Assert.AreEqual(1, s.SessionFactory.Statistics.EntityInsertCount);
+
+ // clean up
+ s.Delete(jboss);
+ s.Transaction.Commit();
+ s.Close();
+ }
+ }
}
}
diff --git a/src/NHibernate.sln b/src/NHibernate.sln
index 67d957ed5d6..2c7f1c7eb97 100644
--- a/src/NHibernate.sln
+++ b/src/NHibernate.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26730.12
+VisualStudioVersion = 15.0.27130.2024
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{593DCEA7-C933-46F3-939F-D8172399AB05}"
ProjectSection(SolutionItems) = preProject
diff --git a/src/NHibernate/Action/BulkOperationCleanupAction.cs b/src/NHibernate/Action/BulkOperationCleanupAction.cs
index 1e6edd1d0b3..53cbaf177bc 100644
--- a/src/NHibernate/Action/BulkOperationCleanupAction.cs
+++ b/src/NHibernate/Action/BulkOperationCleanupAction.cs
@@ -1,8 +1,12 @@
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
using NHibernate.Engine;
using NHibernate.Metadata;
using NHibernate.Persister.Entity;
+using IQueryable = NHibernate.Persister.Entity.IQueryable;
namespace NHibernate.Action
{
@@ -10,7 +14,7 @@ namespace NHibernate.Action
/// Implementation of BulkOperationCleanupAction.
///
[Serializable]
- public partial class BulkOperationCleanupAction: IExecutable
+ public partial class BulkOperationCleanupAction : IExecutable
{
private readonly ISessionImplementor session;
private readonly HashSet affectedEntityNames = new HashSet();
@@ -84,14 +88,8 @@ private bool AffectedEntity(ISet querySpaces, string[] entitySpaces)
return true;
}
- for (int i = 0; i < entitySpaces.Length; i++)
- {
- if (querySpaces.Contains(entitySpaces[i]))
- {
- return true;
- }
- }
- return false;
+
+ return entitySpaces.Any(querySpaces.Contains);
}
#region IExecutable Members
@@ -113,8 +111,8 @@ public void Execute()
public BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess
{
- get
- {
+ get
+ {
return null;
}
}
@@ -133,32 +131,36 @@ public AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProce
private void EvictCollectionRegions()
{
- if (affectedCollectionRoles != null)
+ if (affectedCollectionRoles != null && affectedCollectionRoles.Any())
{
- foreach (string roleName in affectedCollectionRoles)
- {
- session.Factory.EvictCollection(roleName);
- }
+ session.Factory.EvictCollection(affectedCollectionRoles);
}
}
private void EvictEntityRegions()
{
- if (affectedEntityNames != null)
+ if (affectedEntityNames != null && affectedEntityNames.Any())
{
- foreach (string entityName in affectedEntityNames)
- {
- session.Factory.EvictEntity(entityName);
- }
+ session.Factory.EvictEntity(affectedEntityNames);
}
}
#endregion
+ // Since v5.2
+ [Obsolete("This method has no more usage in NHibernate and will be removed in a future version.")]
public virtual void Init()
{
EvictEntityRegions();
EvictCollectionRegions();
}
+
+ // Since v5.2
+ [Obsolete("This method has no more usage in NHibernate and will be removed in a future version.")]
+ public virtual async Task InitAsync(CancellationToken cancellationToken)
+ {
+ await EvictEntityRegionsAsync(cancellationToken);
+ await EvictCollectionRegionsAsync(cancellationToken);
+ }
}
}
diff --git a/src/NHibernate/Async/Action/BulkOperationCleanupAction.cs b/src/NHibernate/Async/Action/BulkOperationCleanupAction.cs
index 899db3bc5d0..c65a41770fc 100644
--- a/src/NHibernate/Async/Action/BulkOperationCleanupAction.cs
+++ b/src/NHibernate/Async/Action/BulkOperationCleanupAction.cs
@@ -10,15 +10,17 @@
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
using NHibernate.Engine;
using NHibernate.Metadata;
using NHibernate.Persister.Entity;
+using IQueryable = NHibernate.Persister.Entity.IQueryable;
namespace NHibernate.Action
{
- using System.Threading.Tasks;
- using System.Threading;
- public partial class BulkOperationCleanupAction: IExecutable
+ public partial class BulkOperationCleanupAction : IExecutable
{
#region IExecutable Members
@@ -57,37 +59,46 @@ public Task ExecuteAsync(CancellationToken cancellationToken)
}
}
- private async Task EvictCollectionRegionsAsync(CancellationToken cancellationToken)
+ private Task EvictCollectionRegionsAsync(CancellationToken cancellationToken)
{
- cancellationToken.ThrowIfCancellationRequested();
- if (affectedCollectionRoles != null)
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return Task.FromCanceled