-
Notifications
You must be signed in to change notification settings - Fork 933
NH-3596 - DistinctRootEntityResultTransformer breaks Cache #383
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
Conversation
Added HQL unit test
@rjperes, can you please add test for case with Fetch(xxx).Eager ? Also |
Didn't you read what I wrote? I said that I only fixed QueryOver, not HQL. And I copied existing tests, didn't create new ones. |
Of course I did not read JIRA. Actually I did so, but after I wrote my |
I thought the solution would be the same, but it wasn't... trickier, I think... |
There is one place you can change to get the same error as with QueryOver QueryLoader.cs L#333 |
[Test] | ||
public void UsingHqlToFutureWithCacheAndTransformerDoesntThrow() | ||
{ | ||
//NH-3596 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is NH-2867
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the same problem
BTW, for HQL it works completely incorrect. It returns 2 roles: null and Role |
Yes, I know... |
It seems that the problem is with self-referenced entities, and not with your solution. Can you adjust tests to use non-recursive entities? |
But why, if this has to be fixed as well? |
"not with your solution"? |
Ok, just forget. I'm talking bullshit. |
:-D |
Ok.... nevermind... We need following tests to cover all the cases: MultiCriteria/MultiQueryOver All of the above with and without cache |
So... what I'm talking about... following test query does not work at all
|
Yes, I know! That's why I said it has an error! But it should work! |
Not as part of solving this issue... The query does not use multiquery/future nor cache. |
But where did that code come from? It's not in my commit, for sure. |
I'm playing with your pull request. So I modified the query (removed multi-query and cahce) to see if this query works on it's own. |
I have code like this in a project (NH 4.0.2): var ordersInHql = session.CreateQuery("from Order o left join fetch o.Details d left join fetch d.Product").List(); And it works perfectly... |
Yes, Order-Details-Product works... But Role-Role-Role does not. And that's why I said this: "It seems that the problem is with self-referenced entities", "All of the above with self-reference and normal entities" |
Yes, you are right. I don't have much time ATM, maybe later, or if you can handle it, fine! BTW, congrats on the new job! ;-) |
Thanks |
{ | ||
//store values in cache | ||
session | ||
.CreateQuery("from Role r left join r.Children left join r.Parent where r.Parent is null") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be
"select r from Role r left join r.Children left join r.Parent where r.Parent is null"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that it is different from the saved query, but it was like this in the unit test (QueryOver version).
TeamCity does that for you!! :-P |
.SetCacheMode(CacheMode.Normal) | ||
.Future<Role>(); | ||
|
||
//get values from cache |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure that this will be from cache?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be, shouldn't it? It's the same query, no parameters...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget that they are future queries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The query cache key will be
"select role0_.Id as Id0_0_, children1_.Id as Id0_1_, role2_.Id as Id0_2_, role0_.Name as Name0_0_, role0_.ParentId as ParentId0_0_, children1_.Name as Name0_1_, children1_.ParentId as ParentId0_1_, children1_.ParentId as ParentId0__, children1_.Id as Id0__, role2_.Name as Name0_2_, role2_.ParentId as ParentId0_2_ from Role role0_ left outer join Role children1_ on role0_.Id=children1_.ParentId left outer join Role role2_ on role0_.ParentId=role2_.Id where role0_.ParentId is null;\r\nselect role0_.Id as Id0_0_, children1_.Id as Id0_1_, role2_.Id as Id0_2_, role0_.Name as Name0_0_, role0_.ParentId as ParentId0_0_, children1_.Name as Name0_1_, children1_.ParentId as ParentId0_1_, children1_.ParentId as ParentId0__, children1_.Id as Id0__, role2_.Name as Name0_2_, role2_.ParentId as ParentId0_2_ from Role role0_ left outer join Role children1_ on role0_.Id=children1_.ParentId left outer join Role role2_ on role0_.ParentId=role2_.Id where role0_.ParentId is null;\r\n"
Which means that both queries' results will go to the same cache item...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other words the first future is pending and not executed before the second one gets executed. So both queries (although being the same) ends-up batched together in a single round-trip to database. So it has nothing to retrieve from cache, since only one actual sql-query is performed.
The previous test has the same issue.
So you need revert last commits and call these methods twice |
And then it brakes.... |
"Which means that both queries' results will go to the same cache item..." |
Ok, just revert last 2 commits, fix HQL queries and call each test method twice... |
Yes, and... no... |
I don't understand what you mean. |
No, it does not work as this... Because this is a future... 2 queries are combined together (it does not matter if they are identical or not), and after then they are treated as one single query. So they miss/hit cache together. So what I'm trying to say, that in your test you actually only put queries to cache, and do not retrieve them See the code: [Test]
public void UsingQueryOverToFutureWithCacheAndTransformerDoesntThrow()
{
//store values in cache
UsingQueryOverToFutureWithCacheAndTransformerDoesntThrowCore();
//get values from cache
UsingQueryOverToFutureWithCacheAndTransformerDoesntThrowCore();
}
private void UsingQueryOverToFutureWithCacheAndTransformerDoesntThrowCore()
{
//NH-3596
using (var session = this.OpenSession())
using (session.BeginTransaction())
{
session
.QueryOver<Role>()
.Where(x => x.Parent == null)
.TransformUsing(Transformers.DistinctRootEntity)
.Cacheable()
.CacheMode(CacheMode.Normal)
.Future(); // schedule query for execution
Role children = null;
Role parent = null;
var roles = session
.QueryOver<Role>()
.Left.JoinAlias(x => x.Children, () => children)
.Left.JoinAlias(x => x.Parent, () => parent)
.TransformUsing(Transformers.DistinctRootEntity)
.Cacheable()
.CacheMode(CacheMode.Normal)
.Future(); // schedule query for execution
var result = roles.ToList(); // both queries executed here in one roundtrip
Assert.AreEqual(5, result.Count);
}
}
[Test]
public void UsingHqlToFutureWithCacheAndTransformerDoesntThrow()
{
//NH-3596
//store values in cache
UsingHqlToFutureWithCacheAndTransformerDoesntThrowCore();
//get values from cache
UsingHqlToFutureWithCacheAndTransformerDoesntThrowCore();
}
private void UsingHqlToFutureWithCacheAndTransformerDoesntThrowCore()
{
using (var session = this.OpenSession())
using (session.BeginTransaction())
{
session
.CreateQuery("select r from Role r left join r.Children left join r.Parent where r.Parent is null")
.SetResultTransformer(Transformers.DistinctRootEntity)
.SetCacheable(true)
.SetCacheMode(CacheMode.Normal)
.Future<Role>(); // schedule query for execution
var roles = session
.CreateQuery("select r from Role r left join r.Children left join r.Parent")
.SetResultTransformer(Transformers.DistinctRootEntity)
.SetCacheable(true)
.SetCacheMode(CacheMode.Normal)
.Future<Role>(); // schedule query for execution
var result = roles.ToList(); // both queries executed here in one roundtrip
Assert.AreEqual(5, result.Count);
}
} |
OK, but that doesn't affect my fix, and also the "bug" I spotted. My fix makes the unit test work, otherwise, it would fail. |
Your fix fixes only half of the problem, only that part when you put results to cache, but does not fix the same problem when you retrieve from cache. |
Great! So you'll only have half the trouble! :-) |
This is inside Find method which is private and used only from SessionImpl.Delete |
Ok, back to our sheeps... I managed to fix QueryOver by application of exactly same changes to MultipleQueriesCacheAssembler.Assemble, and it promoted error in hql to different part... |
I think that the best solution is split MultipleQueriesCacheAssembler to MultipleQueriesCacheAssemblerForMultiQuery and MultipleQueriesCacheAssemblerForCriteria |
Also, please add tests with Order-Details-Product domain, because else branch is not tested.. (This one)
|
"This is inside Find method which is private and used only from SessionImpl.Delete" |
"This is inside Find method which is private and used only from SessionImpl.Delete" |
singleQueryCached.Add(assemblers[0].Disassemble(objToCache, session, owner)); | ||
} | ||
else | ||
if (objToCache != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have rebased this and amended tests for them to actually test caching then retrieving from cache. I have also rewritten them for using multi-query and multi-criteria, since Future does no more use it. They fail, as expected by @hazzik. I cannot push the rebase to show this, it seems "Allow edits from maintainers." is not enabled. |
The affected APIs are now obsoleted, and the replacing ones do not suffer of the bug. |
https://nhibernate.jira.com/browse/NH-3596 (duplicate of https://nhibernate.jira.com/browse/NH-2867, #1243)
Fix for QueryOver and unit test
HQL still not working