Skip to content

Commit bf8056a

Browse files
committed
Fix NH-2673, NH-1090, NH-1344
SVN: trunk@5793
1 parent 2a7cd33 commit bf8056a

File tree

14 files changed

+254
-41
lines changed

14 files changed

+254
-41
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Iesi.Collections.Generic;
2+
3+
namespace NHibernate.Test.NHSpecificTest.NH2673
4+
{
5+
public class Blog
6+
{
7+
public Blog()
8+
{
9+
Posts = new HashedSet<Post>();
10+
Comments = new HashedSet<Comment>();
11+
}
12+
13+
public virtual int Id { get; set; }
14+
public virtual string Author { get; set; }
15+
public virtual string Name { get; set; }
16+
public virtual ISet<Post> Posts { get; set; }
17+
public virtual ISet<Comment> Comments { get; set; }
18+
}
19+
20+
public class Post
21+
{
22+
public virtual int Id { get; protected set; }
23+
public virtual string Title { get; set; }
24+
public virtual string Body { get; set; }
25+
}
26+
27+
28+
public class Comment
29+
{
30+
public virtual int Id { get; protected set; }
31+
public virtual string Title { get; set; }
32+
public virtual string Body { get; set; }
33+
}
34+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
using System;
2+
using System.Collections;
3+
using NHibernate.Cache;
4+
using NHibernate.Cfg;
5+
using NHibernate.Cfg.MappingSchema;
6+
using NHibernate.Mapping.ByCode;
7+
using NHibernate.Transform;
8+
using NUnit.Framework;
9+
using SharpTestsEx;
10+
11+
namespace NHibernate.Test.NHSpecificTest.NH2673
12+
{
13+
public class CachingWithTrasformerTests: TestCaseMappingByCode
14+
{
15+
protected override HbmMapping GetMappings()
16+
{
17+
var mapper = new ConventionModelMapper();
18+
mapper.BeforeMapClass += (inspector, type, map) => map.Id(x => x.Generator(Generators.HighLow));
19+
mapper.BeforeMapClass += (inspector, type, map) => map.Cache(x => x.Usage(CacheUsage.ReadWrite));
20+
mapper.BeforeMapSet += (inspector, property, map) =>
21+
{
22+
map.Cascade(Mapping.ByCode.Cascade.All);
23+
map.Cache(x => x.Usage(CacheUsage.ReadWrite));
24+
};
25+
var mapping = mapper.CompileMappingFor(new[] { typeof(Blog), typeof(Post), typeof(Comment) });
26+
return mapping;
27+
}
28+
29+
protected override void Configure(Cfg.Configuration configuration)
30+
{
31+
configuration.Cache(x =>
32+
{
33+
x.Provider<HashtableCacheProvider>();
34+
x.UseQueryCache = true;
35+
});
36+
}
37+
38+
private class Scenario: IDisposable
39+
{
40+
private readonly ISessionFactory factory;
41+
42+
public Scenario(ISessionFactory factory)
43+
{
44+
this.factory = factory;
45+
using (var session= factory.OpenSession())
46+
using (var tx = session.BeginTransaction())
47+
{
48+
var blog = new Blog { Author = "Gabriel", Name = "Keep on running" };
49+
blog.Posts.Add(new Post { Title = "First post", Body = "Some text" });
50+
blog.Posts.Add(new Post { Title = "Second post", Body = "Some other text" });
51+
blog.Posts.Add(new Post { Title = "Third post", Body = "Third post text" });
52+
53+
54+
blog.Comments.Add(new Comment { Title = "First comment", Body = "Some text" });
55+
blog.Comments.Add(new Comment { Title = "Second comment", Body = "Some other text" });
56+
session.Save(blog);
57+
tx.Commit();
58+
}
59+
}
60+
61+
public void Dispose()
62+
{
63+
using (var session = factory.OpenSession())
64+
using (var tx = session.BeginTransaction())
65+
{
66+
session.CreateQuery("delete from Comment").ExecuteUpdate();
67+
session.CreateQuery("delete from Post").ExecuteUpdate();
68+
session.CreateQuery("delete from Blog").ExecuteUpdate();
69+
tx.Commit();
70+
}
71+
}
72+
}
73+
74+
[Test]
75+
public void WhenQueryThenNotThrows()
76+
{
77+
using (new Scenario(Sfi))
78+
{
79+
using (var session = OpenSession())
80+
using (var tx = session.BeginTransaction())
81+
{
82+
var query = session.CreateQuery("from Blog b where b.Author = : author")
83+
.SetString("author", "Gabriel")
84+
.SetCacheable(true)
85+
.SetResultTransformer(new DistinctRootEntityResultTransformer());
86+
query.Executing(q=> q.List<Blog>()).NotThrows();
87+
tx.Commit();
88+
}
89+
}
90+
}
91+
92+
[Test]
93+
public void WhenCriteriaThenNotThrows()
94+
{
95+
using (new Scenario(Sfi))
96+
{
97+
using (var session = OpenSession())
98+
using (var tx = session.BeginTransaction())
99+
{
100+
var query = session.QueryOver<Blog>().Where(x => x.Author == "Gabriel")
101+
.TransformUsing(new DistinctRootEntityResultTransformer())
102+
.Cacheable();
103+
query.Executing(q => q.List<Blog>()).NotThrows();
104+
tx.Commit();
105+
}
106+
}
107+
}
108+
109+
private class BlogAuthorDto
110+
{
111+
public string BlogName { get; set; }
112+
public string AuthorName { get; set; }
113+
}
114+
115+
private class BlogAuthorTrasformer : IResultTransformer
116+
{
117+
public object TransformTuple(object[] tuple, string[] aliases)
118+
{
119+
return new BlogAuthorDto { BlogName = tuple[0].ToString(), AuthorName = tuple[1].ToString() };
120+
}
121+
122+
public IList TransformList(IList collection)
123+
{
124+
return collection;
125+
}
126+
}
127+
128+
[Test]
129+
public void WhenCriteriaProjectionThenNotThrows()
130+
{
131+
// during the fix of NH-2673 was faund another bug related to cacheability of criteria with projection + trasformer
132+
// then found reported as NH-1090
133+
var transformer = new BlogAuthorTrasformer();
134+
using (new Scenario(Sfi))
135+
{
136+
using (var session = OpenSession())
137+
using (var tx = session.BeginTransaction())
138+
{
139+
var query = session.QueryOver<Blog>().Select(x=> x.Author, x=> x.Name).Where(x => x.Author == "Gabriel")
140+
.TransformUsing(transformer)
141+
.Cacheable();
142+
query.List<BlogAuthorDto>();
143+
tx.Commit();
144+
}
145+
using (var session = OpenSession())
146+
using (var tx = session.BeginTransaction())
147+
{
148+
var query = session.QueryOver<Blog>().Select(x => x.Author, x => x.Name).Where(x => x.Author == "Gabriel")
149+
.TransformUsing(transformer)
150+
.Cacheable();
151+
query.Executing(q => q.List<BlogAuthorDto>()).NotThrows();
152+
tx.Commit();
153+
}
154+
}
155+
}
156+
}
157+
}

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,8 @@
810810
<Compile Include="NHSpecificTest\NH2632\Fixture.cs" />
811811
<Compile Include="NHSpecificTest\NH2660And2661\DomainClass.cs" />
812812
<Compile Include="NHSpecificTest\NH2660And2661\Test.cs" />
813+
<Compile Include="NHSpecificTest\NH2673\Blog.cs" />
814+
<Compile Include="NHSpecificTest\NH2673\CachingWithTrasformerTests.cs" />
813815
<Compile Include="NHSpecificTest\Properties\CompositePropertyRefTest.cs" />
814816
<Compile Include="NHSpecificTest\Properties\DynamicEntityTest.cs" />
815817
<Compile Include="NHSpecificTest\Properties\Model.cs" />

src/NHibernate/Cache/QueryKey.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ public QueryKey(ISessionFactoryImplementor factory, SqlString queryString, Query
6161
hashCode = ComputeHashCode();
6262
}
6363

64+
public bool HasResultTrasformer
65+
{
66+
get { return customTransformer != null; }
67+
}
68+
6469
public QueryKey SetFirstRows(int[] firstRows)
6570
{
6671
multiQueriesFirstRows = firstRows;

src/NHibernate/Cache/StandardQueryCache.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public bool Put(QueryKey key, ICacheAssembler[] returnTypes, IList result, bool
7777
IList cacheable = new List<object>(result.Count + 1) {ts};
7878
for (int i = 0; i < result.Count; i++)
7979
{
80-
if (returnTypes.Length == 1)
80+
if (returnTypes.Length == 1 && !key.HasResultTrasformer)
8181
{
8282
cacheable.Add(returnTypes[0].Disassemble(result[i], session, null));
8383
}

src/NHibernate/Cfg/Loquacious/CacheConfiguration.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,21 @@ public byte DefaultExpiration
3535

3636
public void Provider<TProvider>() where TProvider : ICacheProvider
3737
{
38-
cfg.SetProperty(Environment.CacheProvider, typeof (TProvider).AssemblyQualifiedName);
38+
UseSecondLevelCache = true;
39+
cfg.SetProperty(Environment.CacheProvider, typeof(TProvider).AssemblyQualifiedName);
3940
}
4041

4142
public void QueryCache<TFactory>() where TFactory : IQueryCache
4243
{
44+
UseSecondLevelCache = true;
4345
UseQueryCache = true;
4446
cfg.SetProperty(Environment.QueryCacheFactory, typeof(TFactory).AssemblyQualifiedName);
4547
}
4648

49+
private bool UseSecondLevelCache
50+
{
51+
set { cfg.SetProperty(Environment.UseSecondLevelCache, value.ToString().ToLowerInvariant()); }
52+
}
4753
#endregion
4854
}
4955

@@ -66,6 +72,7 @@ internal Configuration Configuration
6672

6773
public ICacheConfiguration Through<TProvider>() where TProvider : ICacheProvider
6874
{
75+
fc.Configuration.SetProperty(Environment.UseSecondLevelCache, "true");
6976
fc.Configuration.SetProperty(Environment.CacheProvider, typeof(TProvider).AssemblyQualifiedName);
7077
return this;
7178
}
@@ -106,6 +113,8 @@ public QueryCacheConfiguration(CacheConfiguration cc)
106113

107114
public ICacheConfiguration Through<TFactory>() where TFactory : IQueryCache
108115
{
116+
cc.Configuration.SetProperty(Environment.UseSecondLevelCache, "true");
117+
cc.Configuration.SetProperty(Environment.UseQueryCache, "true");
109118
cc.Configuration.SetProperty(Environment.QueryCacheFactory, typeof(TFactory).AssemblyQualifiedName);
110119
return cc;
111120
}

src/NHibernate/Hql/Ast/ANTLR/Loader/QueryLoader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ public IList List(ISessionImplementor session, QueryParameters queryParameters)
300300
return List(session, queryParameters, _queryTranslator.QuerySpaces, _queryReturnTypes);
301301
}
302302

303-
protected override IList GetResultList(IList results, IResultTransformer resultTransformer)
303+
public override IList GetResultList(IList results, IResultTransformer resultTransformer)
304304
{
305305
// meant to handle dynamic instantiation queries...
306306
HolderInstantiator holderInstantiator = HolderInstantiator.GetHolderInstantiator(_selectNewTransformer,

src/NHibernate/Hql/Classic/QueryTranslator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1512,7 +1512,7 @@ protected override object GetResultColumnOrRow(object[] row, IResultTransformer
15121512
}
15131513
}
15141514

1515-
protected override IList GetResultList(IList results, IResultTransformer resultTransformer)
1515+
public override IList GetResultList(IList results, IResultTransformer resultTransformer)
15161516
{
15171517
HolderInstantiator holderInstantiator =
15181518
HolderInstantiator.CreateClassicHolderInstantiator(holderConstructor, resultTransformer);

src/NHibernate/Impl/CriteriaImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class CriteriaImpl : ICriteria
2626
private int timeout = RowSelection.NoValue;
2727
private int fetchSize = RowSelection.NoValue;
2828
private ISessionImplementor session;
29-
private IResultTransformer resultTransformer = CriteriaSpecification.RootEntity;
29+
private IResultTransformer resultTransformer;
3030
private bool cacheable;
3131
private string cacheRegion;
3232
private CacheMode? cacheMode;

src/NHibernate/Impl/MultiCriteriaImpl.cs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using NHibernate.SqlCommand;
1515
using NHibernate.Transform;
1616
using NHibernate.Type;
17+
using NHibernate.Util;
1718

1819
namespace NHibernate.Impl
1920
{
@@ -91,7 +92,6 @@ public IList List()
9192
}
9293
}
9394

94-
9595
private IList ListUsingQueryCache()
9696
{
9797
IQueryCache queryCache = session.Factory.GetQueryCache(cacheRegion);
@@ -141,21 +141,28 @@ private IList ListIgnoreQueryCache()
141141

142142
protected virtual IList GetResultList(IList results)
143143
{
144-
if (resultTransformer != null)
144+
for (int i = 0; i < loaders.Count; i++)
145145
{
146-
for (int i = 0; i < results.Count; i++)
146+
CriteriaLoader loader = loaders[i];
147+
results[i] = loader.GetResultList((IList)results[i], parameters[i].ResultTransformer);
148+
IList tmpResults;
149+
if (resultCollectionGenericType[i] == typeof (object))
147150
{
148-
results[i] = resultTransformer.TransformList((IList)results[i]);
151+
tmpResults = new ArrayList();
152+
}
153+
else
154+
{
155+
tmpResults = (IList) Activator.CreateInstance(typeof (List<>).MakeGenericType(resultCollectionGenericType[i]));
149156
}
157+
ArrayHelper.AddAll(tmpResults, (IList)results[i]);
158+
159+
results[i] = tmpResults;
150160
}
151-
else
161+
if (resultTransformer != null)
152162
{
153163
for (int i = 0; i < results.Count; i++)
154164
{
155-
CriteriaImpl critImp = criteriaQueries[i] as CriteriaImpl;
156-
if (critImp == null || critImp.ResultTransformer == null)
157-
continue;
158-
results[i] = critImp.ResultTransformer.TransformList((IList)results[i]);
165+
results[i] = resultTransformer.TransformList((IList)results[i]);
159166
}
160167
}
161168
return results;
@@ -205,15 +212,7 @@ private void GetResultsFromDatabase(IList results)
205212
hydratedObjects[i] = entitySpan == 0 ? null : new ArrayList(entitySpan);
206213
EntityKey[] keys = new EntityKey[entitySpan];
207214
QueryParameters queryParameters = parameters[i];
208-
IList tmpResults;
209-
if (resultCollectionGenericType[i] == typeof(object))
210-
{
211-
tmpResults = new ArrayList();
212-
}
213-
else
214-
{
215-
tmpResults = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(resultCollectionGenericType[i]));
216-
}
215+
IList tmpResults = new ArrayList();
217216

218217
RowSelection selection = parameters[i].RowSelection;
219218
createSubselects[i] = loader.IsSubselectLoadingEnabled;
@@ -238,6 +237,7 @@ private void GetResultsFromDatabase(IList results)
238237
}
239238
tmpResults.Add(o);
240239
}
240+
241241
results.Add(tmpResults);
242242
reader.NextResult();
243243
}

src/NHibernate/Impl/MultiQueryImpl.cs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,8 @@ protected virtual IList GetResultList(IList results)
453453
for (int i = 0; i < len; ++i)
454454
{
455455
// First use the transformer of each query transformig each row and then the list
456-
results[i] = GetTransformedResults((IList)results[i], GetQueryHolderInstantiator(i));
456+
// DONE: The behavior when the query has a 'new' istead a trasformer is delegated to the Loader
457+
results[i] = translators[i].Loader.GetResultList((IList)results[i], Parameters[i].ResultTransformer);
457458
// then use the MultiQueryTransformer (if it has some sense...) using, as source, the transformed result.
458459
results[i] = GetTransformedResults((IList)results[i], multiqueryHolderInstatiator);
459460
}
@@ -475,15 +476,6 @@ private IList GetTransformedResults(IList source, HolderInstantiator holderInsta
475476
return holderInstantiator.ResultTransformer.TransformList(source);
476477
}
477478

478-
private HolderInstantiator GetQueryHolderInstantiator(int queryPosition)
479-
{
480-
// TODO : we need a test to check the behavior when the query has a 'new' istead a trasformer
481-
// we should take the HolderInstantiator directly from QueryTranslator... taking care with Parameters.
482-
return Parameters[queryPosition].ResultTransformer != null ?
483-
new HolderInstantiator(Parameters[queryPosition].ResultTransformer, translators[queryPosition].ReturnAliases)
484-
: HolderInstantiator.NoopInstantiator;
485-
}
486-
487479
private HolderInstantiator GetMultiQueryHolderInstatiator()
488480
{
489481
return HasMultiQueryResultTrasformer() ? new HolderInstantiator(resultTransformer, null) : HolderInstantiator.NoopInstantiator;

0 commit comments

Comments
 (0)