Skip to content

Add support for query space synchronization #1392

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jun 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/AsyncGenerator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@
applyChanges: true
analyzation:
methodConversion:
- conversion: Copy
name: AfterTransactionCompletionProcess_EvictsFromCache
- conversion: Copy
hasAttributeName: OneTimeSetUpAttribute
- conversion: Copy
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


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<string> clearCalls = new List<string>();
(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);
}
}
}
}
}
163 changes: 98 additions & 65 deletions src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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());
Expand All @@ -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());
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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"));
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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];
Expand All @@ -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"));
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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());
Expand All @@ -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());
}
}

Expand All @@ -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;
Expand Down Expand Up @@ -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();
}
}
}
}
Loading