-
Notifications
You must be signed in to change notification settings - Fork 935
NH-3848 - Tests and fix for HQL #463
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
fredericDelaporte
merged 19 commits into
nhibernate:master
from
itmagination:NH-3848_HQL
Feb 6, 2019
Merged
Changes from 8 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
6a70bfc
Tests for NH-3848
itmagination 86b51e7
Fix using HQL for NH-3848
itmagination ee48f06
Fix compilation after rebase
hazzik dffe832
Fix property implementation according to it's name
hazzik 9f2b84d
Re-implement with accordance to changes on master
hazzik c24ecc1
fixup! Re-implement with accordance to changes on master
hazzik 4803c56
fixup! Tests for NH-3848
hazzik 367bd2f
Cache _canAddFetchedCollectionToCache
hazzik 11ed4ec
Guarantee session closing and use common test base
fredericDelaporte de8caf0
Do minor cleanup
fredericDelaporte 2f66408
Attempt to optimize restriction search logic
bahusoid 511db08
Retype collection fetches
fredericDelaporte 49e9401
Merge branch 'master' into NH-3848_HQL
fredericDelaporte 24a336a
Merge branch 'master' into NH-3848_HQL
hazzik d399297
Exclude only filtered collections from caching
hazzik 6111a15
Apply suggestions from @bahusoid
hazzik fc3d51d
Merge branch 'master' into NH-3848_HQL
fredericDelaporte a677801
Merge branch 'NH-3848_HQL' of https://github.com/itmagination/nhibern…
fredericDelaporte a5d52f9
Regen async
fredericDelaporte File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
76 changes: 76 additions & 0 deletions
76
src/NHibernate.Test/NHSpecificTest/NH3848/HqlTestFixture.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using NHibernate.Transform; | ||
using NUnit.Framework; | ||
|
||
namespace NHibernate.Test.NHSpecificTest.NH3848 | ||
{ | ||
public class HqlTestFixture : TestFixture | ||
{ | ||
[Ignore("We can't write such query using hql, because we can't use 'with' clause when we're fetching collection.")] | ||
public override void ChildCollectionsFromLeftOuterJoinWithOnClauseRestrictionOnCollectionShouldNotBeInSecondLevelCache() | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
protected override IList<Customer> GetCustomersWithFetchedOrdersWithoutRestrictions(ISession session) | ||
{ | ||
var query = session.CreateQuery("from Customer as c left join fetch c.Orders as o"); | ||
query.SetResultTransformer(new DistinctRootEntityResultTransformer()); | ||
return query.List<Customer>(); | ||
} | ||
|
||
protected override IList<Customer> GetCustomersWithOrdersEagerLoaded(ISession session) | ||
{ | ||
var query = session.CreateQuery("from Customer as c left join fetch c.Orders as o"); | ||
query.SetResultTransformer(new DistinctRootEntityResultTransformer()); | ||
return query.List<Customer>(); | ||
} | ||
|
||
//We can't write such query using hql, because we can't use 'with' clause when we're fetching collection. | ||
protected override IList<Customer> GetCustomersByOrderNumberUsingOnClause(ISession session, int orderNumber) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
protected override IList<Customer> GetCustomersByOrderNumberUsingWhereClause(ISession session, int orderNumber) | ||
{ | ||
var numberParameterName = "number"; | ||
var query = session.CreateQuery(string.Format("from Customer as c " + | ||
"left join fetch c.Orders as o " + | ||
"where o.Number = :{0}", numberParameterName)); | ||
query.SetParameter(numberParameterName, orderNumber); | ||
return query.List<Customer>(); | ||
} | ||
|
||
protected override IList<Customer> GetCustomersByNameUsingWhereClause(ISession session, string customerName) | ||
{ | ||
var nameParameterName = "name"; | ||
var query = session.CreateQuery(string.Format("from Customer as c " + | ||
"left join fetch c.Orders as o " + | ||
"where c.Name = :{0}", nameParameterName)); | ||
query.SetParameter(nameParameterName, customerName); | ||
query.SetResultTransformer(new DistinctRootEntityResultTransformer()); | ||
return query.List<Customer>(); | ||
} | ||
|
||
protected override IList<Customer> GetCustomersByOrderNumberUsingSubqueriesAndByNameUsingWhereClause(ISession session, int orderNumber, string customerName) | ||
{ | ||
var nameParameterName = "name"; | ||
var numberParameterName = "number"; | ||
var query = session.CreateQuery(string.Format("from Customer as c " + | ||
"left join fetch c.Orders as o " + | ||
"where c.Name = :{0} and " + | ||
"c.Id in (select c1.Id from Customer as c1 left join c1.Orders as o2 where o2.Number = :{1})", nameParameterName, numberParameterName)); | ||
query.SetParameter(nameParameterName, customerName); | ||
query.SetParameter(numberParameterName, orderNumber); | ||
query.SetResultTransformer(new DistinctRootEntityResultTransformer()); | ||
return query.List<Customer>(); | ||
} | ||
|
||
protected override IList<Customer> GetAllCustomers(ISession session) | ||
{ | ||
return session.CreateQuery("from Customer as c").List<Customer>(); | ||
} | ||
} | ||
} |
266 changes: 266 additions & 0 deletions
266
src/NHibernate.Test/NHSpecificTest/NH3848/TestFixture.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Data; | ||
using System.Linq; | ||
using System.Linq.Expressions; | ||
using NHibernate.Cache; | ||
using NHibernate.Cfg; | ||
using NHibernate.Cfg.MappingSchema; | ||
using NHibernate.Mapping.ByCode; | ||
using NUnit.Framework; | ||
|
||
namespace NHibernate.Test.NHSpecificTest.NH3848 | ||
{ | ||
public abstract class TestFixture : TestCaseMappingByCode | ||
fredericDelaporte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
protected Customer Customer1; | ||
protected Customer Customer2; | ||
protected Customer Customer3; | ||
protected const int OrderNumber = 2; | ||
|
||
protected override HbmMapping GetMappings() | ||
{ | ||
var mapper = new ModelMapper(); | ||
mapper.Class<Customer>(rc => | ||
{ | ||
rc.Table("Customers"); | ||
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); | ||
rc.Property(x => x.Name); | ||
rc.Set(x => x.Orders, m => | ||
{ | ||
m.Inverse(true); | ||
m.Key(k => | ||
{ | ||
k.Column("CustomerId"); | ||
k.NotNullable(true); | ||
}); | ||
m.Cascade(Mapping.ByCode.Cascade.All.Include(Mapping.ByCode.Cascade.DeleteOrphans)); | ||
m.Cache(c => c.Usage(CacheUsage.ReadWrite)); | ||
}, m => m.OneToMany()); | ||
}); | ||
|
||
mapper.Class<Order>(rc => | ||
{ | ||
rc.Table("Orders"); | ||
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); | ||
rc.Property(x => x.Number); | ||
rc.ManyToOne(x => x.Customer, m => m.Column("CustomerId")); | ||
rc.Cache(c => c.Usage(CacheUsage.ReadWrite)); | ||
}); | ||
|
||
return mapper.CompileMappingForAllExplicitlyAddedEntities(); | ||
} | ||
|
||
protected override void Configure(Configuration configuration) | ||
{ | ||
base.Configure(configuration); | ||
configuration.Cache(c => | ||
{ | ||
c.UseQueryCache = true; | ||
c.Provider<HashtableCacheProvider>(); | ||
}); | ||
} | ||
|
||
protected override void OnSetUp() | ||
{ | ||
using (var session = OpenSession()) | ||
using (var transaction = session.BeginTransaction()) | ||
{ | ||
Customer1 = new Customer { Name = "First Customer" }; | ||
|
||
Customer2 = new Customer { Name = "Second Customer" }; | ||
|
||
Customer3 = new Customer { Name = "Third Customer" }; | ||
|
||
var customer1Order1 = new Order { Number = 1 }; | ||
Customer1.AddOrder(customer1Order1); | ||
|
||
var customer1Order2 = new Order { Number = 2 }; | ||
Customer1.AddOrder(customer1Order2); | ||
|
||
var customer2Order1 = new Order { Number = 1 }; | ||
Customer2.AddOrder(customer2Order1); | ||
|
||
var customer2Order2 = new Order { Number = 2 }; | ||
Customer2.AddOrder(customer2Order2); | ||
|
||
var customer3Order1 = new Order { Number = 1 }; | ||
Customer3.AddOrder(customer3Order1); | ||
|
||
session.Save(Customer1); | ||
session.Save(Customer2); | ||
session.Save(Customer3); | ||
|
||
transaction.Commit(); | ||
session.Flush(); | ||
} | ||
} | ||
|
||
protected override void OnTearDown() | ||
{ | ||
ClearSecondLevelCacheFor(typeof(Customer)); | ||
ClearCollectionCache<Customer>(n => n.Orders); | ||
ClearSecondLevelCacheFor(typeof(Order)); | ||
|
||
using (var session = OpenSession()) | ||
using (var transaction = session.BeginTransaction()) | ||
{ | ||
session.Delete("from System.Object"); | ||
|
||
session.Flush(); | ||
transaction.Commit(); | ||
} | ||
} | ||
|
||
[Test] | ||
public virtual void ChildCollectionsFromLeftOuterJoinWithOnClauseRestrictionOnCollectionShouldNotBeInSecondLevelCache() | ||
{ | ||
var firstSession = OpenSession(); | ||
fredericDelaporte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
var customersWithOrderNumberEqualsTo2 = GetCustomersByOrderNumberUsingOnClause(firstSession, OrderNumber); | ||
|
||
var secondSession = OpenSession(); | ||
var customers = GetAllCustomers(secondSession); | ||
|
||
Assert.That(customersWithOrderNumberEqualsTo2.Single(n => n.Id == Customer1.Id).Orders, Has.Count.EqualTo(Customer1.Orders.Count(n => n.Number == OrderNumber))); | ||
Assert.That(customersWithOrderNumberEqualsTo2.Single(n => n.Id == Customer2.Id).Orders, Has.Count.EqualTo(Customer2.Orders.Count(n => n.Number == OrderNumber))); | ||
Assert.That(customersWithOrderNumberEqualsTo2.Single(n => n.Id == Customer3.Id).Orders, Has.Count.EqualTo(Customer3.Orders.Count(n => n.Number == OrderNumber))); | ||
|
||
Assert.That(customers.Single(n => n.Id == Customer1.Id).Orders, Has.Count.EqualTo(Customer1.Orders.Count)); | ||
Assert.That(customers.Single(n => n.Id == Customer2.Id).Orders, Has.Count.EqualTo(Customer2.Orders.Count)); | ||
Assert.That(customers.Single(n => n.Id == Customer3.Id).Orders, Has.Count.EqualTo(Customer3.Orders.Count)); | ||
|
||
firstSession.Dispose(); | ||
secondSession.Dispose(); | ||
} | ||
|
||
[Test] | ||
public void ChildCollectionsFromLeftOuterJoinWithWhereClauseRestrictionOnCollectionShouldBeInSecondLevelCache() | ||
{ | ||
var firstSession = OpenSession(); | ||
var customersWithOrderNumberEqualsTo2 = GetCustomersByOrderNumberUsingWhereClause(firstSession, OrderNumber); | ||
|
||
var secondSession = OpenSession(); | ||
var customers = GetAllCustomers(secondSession); | ||
|
||
Assert.That(customersWithOrderNumberEqualsTo2.Single(n => n.Id == Customer1.Id).Orders, Has.Count.EqualTo(Customer1.Orders.Count(n => n.Number == OrderNumber))); | ||
Assert.That(customersWithOrderNumberEqualsTo2.Single(n => n.Id == Customer2.Id).Orders, Has.Count.EqualTo(Customer2.Orders.Count(n => n.Number == OrderNumber))); | ||
|
||
Assert.That(customers.Single(n => n.Id == Customer3.Id).Orders, Has.Count.EqualTo(Customer3.Orders.Count)); | ||
Assert.That(customers.Single(n => n.Id == Customer1.Id).Orders, Has.Count.EqualTo(Customer1.Orders.Count)); | ||
Assert.That(customers.Single(n => n.Id == Customer2.Id).Orders, Has.Count.EqualTo(Customer2.Orders.Count)); | ||
|
||
firstSession.Dispose(); | ||
secondSession.Dispose(); | ||
} | ||
|
||
[Test] | ||
public void ChildCollectionsEagerFetchedShouldBeInSecondLevelCache() | ||
{ | ||
var firstSession = OpenSession(); | ||
var customersWithOrderNumberEqualsTo2 = GetCustomersWithOrdersEagerLoaded(firstSession); | ||
|
||
using (IDbCommand cmd = OpenSession().Connection.CreateCommand()) | ||
{ | ||
cmd.CommandText = "DELETE FROM Orders;"; | ||
cmd.ExecuteNonQuery(); | ||
cmd.Connection.Close(); | ||
} | ||
|
||
var secondSession = OpenSession(); | ||
var customers = GetAllCustomers(secondSession); | ||
|
||
|
||
Assert.That(customersWithOrderNumberEqualsTo2.Single(n => n.Id == Customer1.Id).Orders, Has.Count.EqualTo(Customer1.Orders.Count)); | ||
Assert.That(customersWithOrderNumberEqualsTo2.Single(n => n.Id == Customer2.Id).Orders, Has.Count.EqualTo(Customer2.Orders.Count)); | ||
|
||
Assert.That(customers.Single(n => n.Id == Customer3.Id).Orders, Has.Count.EqualTo(Customer3.Orders.Count)); | ||
Assert.That(customers.Single(n => n.Id == Customer1.Id).Orders, Has.Count.EqualTo(Customer1.Orders.Count)); | ||
Assert.That(customers.Single(n => n.Id == Customer2.Id).Orders, Has.Count.EqualTo(Customer2.Orders.Count)); | ||
|
||
firstSession.Dispose(); | ||
secondSession.Dispose(); | ||
} | ||
|
||
[Test] | ||
public void ChildCollectionsFromLeftOuterJoinWithWhereClauseRestrictionOnRootShouldBeInSecondLevelCache() | ||
{ | ||
var firstSession = OpenSession(); | ||
var customersWithOrderNumberEqualsTo2 = GetCustomersByNameUsingWhereClause(firstSession, "First Customer"); | ||
|
||
|
||
using (IDbCommand cmd = OpenSession().Connection.CreateCommand()) | ||
{ | ||
cmd.CommandText = "DELETE FROM Orders;"; | ||
cmd.ExecuteNonQuery(); | ||
cmd.Connection.Close(); | ||
} | ||
|
||
var secondSession = OpenSession(); | ||
var customers = secondSession.Get<Customer>(Customer1.Id); | ||
|
||
Assert.That(customersWithOrderNumberEqualsTo2.Single(n => n.Id == Customer1.Id).Orders, Has.Count.EqualTo(Customer1.Orders.Count)); | ||
Assert.That(customers.Orders, Has.Count.EqualTo(Customer1.Orders.Count)); | ||
|
||
firstSession.Dispose(); | ||
secondSession.Dispose(); | ||
} | ||
|
||
[Test] | ||
public void ChildCollectionsFromLeftOuterJoinShouldBeInSecondLevelCacheIfQueryContainsSubqueryWithRestrictionOnLeftOuterJoin() | ||
{ | ||
var firstSession = OpenSession(); | ||
var customersWithOrderNumberEqualsTo2 = GetCustomersByOrderNumberUsingSubqueriesAndByNameUsingWhereClause(firstSession, OrderNumber, Customer1.Name); | ||
|
||
var secondSession = OpenSession(); | ||
var customers = GetAllCustomers(secondSession); | ||
|
||
Assert.That(customersWithOrderNumberEqualsTo2.Single(n => n.Id == Customer1.Id).Orders, Has.Count.EqualTo(Customer1.Orders.Count)); | ||
|
||
using (IDbCommand cmd = OpenSession().Connection.CreateCommand()) | ||
{ | ||
cmd.CommandText = "DELETE FROM Orders;"; | ||
cmd.ExecuteNonQuery(); | ||
cmd.Connection.Close(); | ||
} | ||
|
||
Assert.That(customers.Single(n => n.Id == Customer1.Id).Orders, Has.Count.EqualTo(Customer1.Orders.Count)); | ||
Assert.That(customers.Single(n => n.Id == Customer2.Id).Orders, Has.Count.EqualTo(0)); | ||
Assert.That(customers.Single(n => n.Id == Customer3.Id).Orders, Has.Count.EqualTo(0)); | ||
|
||
firstSession.Dispose(); | ||
secondSession.Dispose(); | ||
} | ||
|
||
protected void ClearSecondLevelCacheFor(System.Type entity) | ||
{ | ||
var entityName = entity.FullName; | ||
Sfi.EvictEntity(entityName); | ||
var entityPersister = Sfi.GetEntityPersister(entityName); | ||
if (!entityPersister.HasCache) | ||
return; | ||
|
||
IReadOnlyCollection<string> querySpaces = entityPersister.QuerySpaces; | ||
Sfi.UpdateTimestampsCache.Invalidate(querySpaces); | ||
} | ||
|
||
protected void ClearCollectionCache<T>(Expression<Func<T, IEnumerable>> pathToCollection) | ||
{ | ||
var rootEntityTypeFullPath = typeof(T).FullName; | ||
var memberExpression = pathToCollection.Body as MemberExpression; | ||
if (memberExpression == null) | ||
throw new ArgumentException("pathToCollection should be member expression"); | ||
|
||
var role = string.Format("{0}.{1}", rootEntityTypeFullPath, memberExpression.Member.Name); | ||
Sfi.EvictCollection(role); | ||
} | ||
|
||
protected abstract IList<Customer> GetCustomersWithFetchedOrdersWithoutRestrictions(ISession session); | ||
protected abstract IList<Customer> GetCustomersWithOrdersEagerLoaded(ISession session); | ||
protected abstract IList<Customer> GetCustomersByOrderNumberUsingOnClause(ISession session, int orderNumber); | ||
protected abstract IList<Customer> GetCustomersByOrderNumberUsingWhereClause(ISession session, int orderNumber); | ||
protected abstract IList<Customer> GetCustomersByNameUsingWhereClause(ISession session, string customerName); | ||
protected abstract IList<Customer> GetCustomersByOrderNumberUsingSubqueriesAndByNameUsingWhereClause(ISession session, int orderNumber, string customerName); | ||
protected abstract IList<Customer> GetAllCustomers(ISession session); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.