From 0bed7d901752cc9dfd362a902b3cc283066874dd Mon Sep 17 00:00:00 2001 From: Ricardo Peres Date: Tue, 25 Nov 2014 18:09:52 +0000 Subject: [PATCH 1/5] Unit test for NH-3596 --- .../NHSpecificTest/NH3596/Blog.cs | 34 ++++++ .../NH3596/CachingWithTransformerTests.cs | 100 ++++++++++++++++++ src/NHibernate.Test/NHibernate.Test.csproj | 2 + 3 files changed, 136 insertions(+) create mode 100644 src/NHibernate.Test/NHSpecificTest/NH3596/Blog.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs diff --git a/src/NHibernate.Test/NHSpecificTest/NH3596/Blog.cs b/src/NHibernate.Test/NHSpecificTest/NH3596/Blog.cs new file mode 100644 index 00000000000..b6959825835 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3596/Blog.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.NH3596 +{ + public class Blog + { + public Blog() + { + Posts = new HashSet(); + Comments = new HashSet(); + } + + public virtual int Id { get; set; } + public virtual string Author { get; set; } + public virtual string Name { get; set; } + public virtual ISet Posts { get; set; } + public virtual ISet Comments { get; set; } + } + + public class Post + { + public virtual int Id { get; protected set; } + public virtual string Title { get; set; } + public virtual string Body { get; set; } + } + + + public class Comment + { + public virtual int Id { get; protected set; } + public virtual string Title { get; set; } + public virtual string Body { get; set; } + } +} \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs b/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs new file mode 100644 index 00000000000..39303012462 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections; +using System.Linq; +using NHibernate.Cache; +using NHibernate.Cfg; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH3596 +{ + public class CachingWithTransformerTests: TestCaseMappingByCode + { + protected override HbmMapping GetMappings() + { + var mapper = new ConventionModelMapper(); + mapper.BeforeMapClass += (inspector, type, map) => map.Id(x => x.Generator(Generators.HighLow)); + mapper.BeforeMapClass += (inspector, type, map) => map.Cache(x => x.Usage(CacheUsage.ReadWrite)); + mapper.BeforeMapClass += (inspector, type, map) => map.Table(type.Name + "s"); + mapper.BeforeMapSet += (inspector, property, map) => + { + map.Cascade(Mapping.ByCode.Cascade.All); + map.Cache(x => x.Usage(CacheUsage.ReadWrite)); + }; + var mapping = mapper.CompileMappingFor(new[] { typeof(Blog), typeof(Post), typeof(Comment) }); + return mapping; + } + + protected override void Configure(Cfg.Configuration configuration) + { + configuration.Cache(x => + { + x.Provider(); + x.UseQueryCache = true; + }); + } + + private class Scenario: IDisposable + { + private readonly ISessionFactory factory; + + public Scenario(ISessionFactory factory) + { + this.factory = factory; + using (var session= factory.OpenSession()) + using (var tx = session.BeginTransaction()) + { + var blog = new Blog { Author = "Gabriel", Name = "Keep on running" }; + blog.Posts.Add(new Post { Title = "First post", Body = "Some text" }); + blog.Posts.Add(new Post { Title = "Second post", Body = "Some other text" }); + blog.Posts.Add(new Post { Title = "Third post", Body = "Third post text" }); + + + blog.Comments.Add(new Comment { Title = "First comment", Body = "Some text" }); + blog.Comments.Add(new Comment { Title = "Second comment", Body = "Some other text" }); + session.Save(blog); + tx.Commit(); + } + } + + public void Dispose() + { + using (var session = factory.OpenSession()) + using (var tx = session.BeginTransaction()) + { + session.CreateQuery("delete from Comment").ExecuteUpdate(); + session.CreateQuery("delete from Post").ExecuteUpdate(); + session.CreateQuery("delete from Blog").ExecuteUpdate(); + tx.Commit(); + } + } + } + + [Test] + public void WhenQueryToFutureWithTransformetThenNotThrows() + { + //NH-3596 + using (new Scenario(Sfi)) + using (var session = this.OpenSession()) + { + var futureblogs = session.QueryOver() + .Where(x => x.Author == "Gabriel") + .Fetch(x => x.Posts).Eager + .TransformUsing(new DistinctRootEntityResultTransformer()) + .Cacheable() + .CacheRegion("") + .Future(); + + Assert.IsNotNull(futureblogs); + + var blogs = futureblogs.ToList(); + + Assert.IsNotNull(blogs); + Assert.IsNotEmpty(blogs); + } + + } + } +} \ No newline at end of file diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index c60b89ab659..01a20e7e090 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -696,6 +696,8 @@ + + From a545396837c69872020430e224a9312897033ddc Mon Sep 17 00:00:00 2001 From: Ricardo Peres Date: Wed, 26 Nov 2014 10:24:47 +0000 Subject: [PATCH 2/5] Fix and unit test from NH-3737 --- .../NHSpecificTest/NH3596/Blog.cs | 34 ---- .../NH3596/CachingWithTransformerTests.cs | 159 +++++++++++------- src/NHibernate.Test/NHibernate.Test.csproj | 1 - .../Impl/MultipleQueriesCacheAssembler.cs | 9 +- 4 files changed, 108 insertions(+), 95 deletions(-) delete mode 100644 src/NHibernate.Test/NHSpecificTest/NH3596/Blog.cs diff --git a/src/NHibernate.Test/NHSpecificTest/NH3596/Blog.cs b/src/NHibernate.Test/NHSpecificTest/NH3596/Blog.cs deleted file mode 100644 index b6959825835..00000000000 --- a/src/NHibernate.Test/NHSpecificTest/NH3596/Blog.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; - -namespace NHibernate.Test.NHSpecificTest.NH3596 -{ - public class Blog - { - public Blog() - { - Posts = new HashSet(); - Comments = new HashSet(); - } - - public virtual int Id { get; set; } - public virtual string Author { get; set; } - public virtual string Name { get; set; } - public virtual ISet Posts { get; set; } - public virtual ISet Comments { get; set; } - } - - public class Post - { - public virtual int Id { get; protected set; } - public virtual string Title { get; set; } - public virtual string Body { get; set; } - } - - - public class Comment - { - public virtual int Id { get; protected set; } - public virtual string Title { get; set; } - public virtual string Body { get; set; } - } -} \ No newline at end of file diff --git a/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs b/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs index 39303012462..6afd9cc6513 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs @@ -1,100 +1,141 @@ -using System; -using System.Collections; +using System.Collections.Generic; using System.Linq; using NHibernate.Cache; using NHibernate.Cfg; using NHibernate.Cfg.MappingSchema; using NHibernate.Mapping.ByCode; +using NHibernate.Mapping.ByCode.Conformist; using NHibernate.Transform; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.NH3596 { + public class EntityBase + { + public virtual int Id { get; set; } + } + + public class Role : EntityBase + { + public virtual string Name { get; set; } + public virtual Role Parent { get; set; } + public virtual IList Children { get; set; } + } + + public class RoleMap : ClassMapping + { + public RoleMap() + { + Cache(x => x.Usage(CacheUsage.ReadOnly)); + Id(x => x.Id, x => x.Generator(Generators.Identity)); + Property(x => x.Name); + ManyToOne(x => x.Parent, x => + { + x.Column("ParentId"); + x.NotNullable(false); + }); + Bag(x => x.Children, x => + { + x.Cascade(Mapping.ByCode.Cascade.All); + x.Key(y => y.Column("ParentId")); + }, x => x.OneToMany()); + } + } + public class CachingWithTransformerTests: TestCaseMappingByCode { protected override HbmMapping GetMappings() { - var mapper = new ConventionModelMapper(); - mapper.BeforeMapClass += (inspector, type, map) => map.Id(x => x.Generator(Generators.HighLow)); - mapper.BeforeMapClass += (inspector, type, map) => map.Cache(x => x.Usage(CacheUsage.ReadWrite)); - mapper.BeforeMapClass += (inspector, type, map) => map.Table(type.Name + "s"); - mapper.BeforeMapSet += (inspector, property, map) => - { - map.Cascade(Mapping.ByCode.Cascade.All); - map.Cache(x => x.Usage(CacheUsage.ReadWrite)); - }; - var mapping = mapper.CompileMappingFor(new[] { typeof(Blog), typeof(Post), typeof(Comment) }); + var mapper = new ModelMapper(); + mapper.AddMapping(); + var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities(); return mapping; } - protected override void Configure(Cfg.Configuration configuration) + protected override void OnSetUp() { - configuration.Cache(x => - { - x.Provider(); - x.UseQueryCache = true; - }); - } + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var parentRoles = new List() + { + new Role() { Name = "Admin", Children = null, Parent = null }, + new Role() { Name = "Manager", Children = null, Parent = null }, + new Role() { Name = "Support", Children = null, Parent = null } + }; - private class Scenario: IDisposable - { - private readonly ISessionFactory factory; + var childRoles = new List() + { + new Role() { Name = "Manager-Secretary", Children = null, Parent = parentRoles.FirstOrDefault(x => x.Name == "Manager") }, + new Role() { Name = "Superviser", Children = null, Parent = parentRoles.FirstOrDefault(x => x.Name == "Manager") } + }; - public Scenario(ISessionFactory factory) - { - this.factory = factory; - using (var session= factory.OpenSession()) - using (var tx = session.BeginTransaction()) + foreach (var parentRole in parentRoles) { - var blog = new Blog { Author = "Gabriel", Name = "Keep on running" }; - blog.Posts.Add(new Post { Title = "First post", Body = "Some text" }); - blog.Posts.Add(new Post { Title = "Second post", Body = "Some other text" }); - blog.Posts.Add(new Post { Title = "Third post", Body = "Third post text" }); - + parentRole.Children = new List(childRoles.Where(x => x.Parent == parentRole)); - blog.Comments.Add(new Comment { Title = "First comment", Body = "Some text" }); - blog.Comments.Add(new Comment { Title = "Second comment", Body = "Some other text" }); - session.Save(blog); - tx.Commit(); + session.Save(parentRole); } + + session.Flush(); + transaction.Commit(); } + } - public void Dispose() + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) { - using (var session = factory.OpenSession()) - using (var tx = session.BeginTransaction()) - { - session.CreateQuery("delete from Comment").ExecuteUpdate(); - session.CreateQuery("delete from Post").ExecuteUpdate(); - session.CreateQuery("delete from Blog").ExecuteUpdate(); - tx.Commit(); - } + session.Delete("from System.Object"); + + session.Flush(); + transaction.Commit(); } } + protected override void Configure(Cfg.Configuration configuration) + { + base.Configure(configuration); + + configuration.Cache(x => + { + x.Provider(); + x.UseQueryCache = true; + }); + } + [Test] - public void WhenQueryToFutureWithTransformetThenNotThrows() + public void WhenQueryToFutureWithTransformerThenNotThrows() { //NH-3596 - using (new Scenario(Sfi)) using (var session = this.OpenSession()) + using (session.BeginTransaction()) { - var futureblogs = session.QueryOver() - .Where(x => x.Author == "Gabriel") - .Fetch(x => x.Posts).Eager - .TransformUsing(new DistinctRootEntityResultTransformer()) - .Cacheable() - .CacheRegion("") - .Future(); + var roles = session + .QueryOver() + .Where(x => x.Parent == null) + .TransformUsing(Transformers.DistinctRootEntity) + .Cacheable() + .CacheMode(CacheMode.Normal) + .Future(); - Assert.IsNotNull(futureblogs); + Role children = null; + Role parent = null; - var blogs = futureblogs.ToList(); + session + .QueryOver() + .Left.JoinAlias(x => x.Children, () => children) + .Left.JoinAlias(x => x.Parent, () => parent) + .TransformUsing(Transformers.DistinctRootEntity) + .Cacheable() + .CacheMode(CacheMode.Normal) + .Future(); - Assert.IsNotNull(blogs); - Assert.IsNotEmpty(blogs); - } + var result = roles.ToList(); + Assert.AreEqual(3, result.Count); + } } } } \ No newline at end of file diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 01a20e7e090..e26b526ed61 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -696,7 +696,6 @@ - diff --git a/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs b/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs index bfb354e5f87..8f5dcf30a48 100644 --- a/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs +++ b/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs @@ -34,7 +34,14 @@ public object Disassemble(object value, ISessionImplementor session, object owne } else { - singleQueryCached.Add(TypeHelper.Disassemble((object[]) objToCache, assemblers, null, session, null)); + var valuesToCache = objToCache as object[]; + + if (valuesToCache == null) + { + valuesToCache = new object[] { objToCache }; + } + + singleQueryCached.Add(TypeHelper.Disassemble(valuesToCache, assemblers, null, session, null)); } } cacheable.Add(singleQueryCached); From 0e201b211e3733bf178b28bb7b2e91c1cc194c25 Mon Sep 17 00:00:00 2001 From: Ricardo Peres Date: Wed, 26 Nov 2014 12:26:10 +0000 Subject: [PATCH 3/5] Improvements Added HQL unit test --- .../NH3596/CachingWithTransformerTests.cs | 40 +++++++++++++++++-- .../Impl/MultipleQueriesCacheAssembler.cs | 24 +++++++---- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs b/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs index 6afd9cc6513..dd0b754da46 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs @@ -106,13 +106,14 @@ protected override void Configure(Cfg.Configuration configuration) } [Test] - public void WhenQueryToFutureWithTransformerThenNotThrows() + public void UsingQueryOverToFutureWithCacheAndTransformerDoesntThrow() { //NH-3596 using (var session = this.OpenSession()) using (session.BeginTransaction()) { - var roles = session + //store values in cache + session .QueryOver() .Where(x => x.Parent == null) .TransformUsing(Transformers.DistinctRootEntity) @@ -123,7 +124,8 @@ public void WhenQueryToFutureWithTransformerThenNotThrows() Role children = null; Role parent = null; - session + //get values from cache + var roles = session .QueryOver() .Left.JoinAlias(x => x.Children, () => children) .Left.JoinAlias(x => x.Parent, () => parent) @@ -134,7 +136,37 @@ public void WhenQueryToFutureWithTransformerThenNotThrows() var result = roles.ToList(); - Assert.AreEqual(3, result.Count); + Assert.AreEqual(5, result.Count); + } + } + + [Test] + public void UsingHqlToFutureWithCacheAndTransformerDoesntThrow() + { + //NH-3596 + using (var session = this.OpenSession()) + using (session.BeginTransaction()) + { + //store values in cache + session + .CreateQuery("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(); + + //get values from cache + var roles = session + .CreateQuery("from Role r left join r.Children left join r.Parent") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetCacheable(true) + .SetCacheMode(CacheMode.Normal) + .Future(); + + var result = roles.ToList(); + + //doesn't work + Assert.AreEqual(5, result.Count); } } } diff --git a/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs b/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs index 8f5dcf30a48..e4ba00617ce 100644 --- a/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs +++ b/src/NHibernate/Impl/MultipleQueriesCacheAssembler.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Generic; +using System.Linq; using NHibernate.Cache; using NHibernate.Engine; using NHibernate.Type; @@ -28,20 +29,29 @@ public object Disassemble(object value, ISessionImplementor session, object owne var singleQueryCached = new List(); foreach (object objToCache in itemList) { - if (assemblers.Length == 1) - { - singleQueryCached.Add(assemblers[0].Disassemble(objToCache, session, owner)); - } - else + if (objToCache != null) { var valuesToCache = objToCache as object[]; + var assemblersToCache = assemblers; - if (valuesToCache == null) + if (valuesToCache != null) + { + assemblersToCache = assemblers.Where((x, index) => valuesToCache[index] != null).ToArray(); + valuesToCache = valuesToCache.Where(x => x != null).ToArray(); + } + else { valuesToCache = new object[] { objToCache }; } - singleQueryCached.Add(TypeHelper.Disassemble(valuesToCache, assemblers, null, session, null)); + if (valuesToCache.Length == 1) + { + singleQueryCached.Add(assemblers[0].Disassemble(valuesToCache[0], session, owner)); + } + else + { + singleQueryCached.Add(TypeHelper.Disassemble(valuesToCache, assemblersToCache, null, session, null)); + } } } cacheable.Add(singleQueryCached); From e1876e6bf4b078e1779fe9cf102b8775f49b9091 Mon Sep 17 00:00:00 2001 From: Ricardo Peres Date: Thu, 27 Nov 2014 11:41:30 +0000 Subject: [PATCH 4/5] Fixed HQL and QueryOver queries --- .../NH3596/CachingWithTransformerTests.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs b/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs index dd0b754da46..05841d6f47e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs @@ -112,21 +112,24 @@ public void UsingQueryOverToFutureWithCacheAndTransformerDoesntThrow() using (var session = this.OpenSession()) using (session.BeginTransaction()) { + Role children = null; + Role parent = null; + //store values in cache session .QueryOver() .Where(x => x.Parent == null) + .Left.JoinAlias(x => x.Children, () => children) + .Left.JoinAlias(x => x.Parent, () => parent) .TransformUsing(Transformers.DistinctRootEntity) .Cacheable() .CacheMode(CacheMode.Normal) .Future(); - Role children = null; - Role parent = null; - //get values from cache var roles = session .QueryOver() + .Where(x => x.Parent == null) .Left.JoinAlias(x => x.Children, () => children) .Left.JoinAlias(x => x.Parent, () => parent) .TransformUsing(Transformers.DistinctRootEntity) @@ -149,7 +152,7 @@ public void UsingHqlToFutureWithCacheAndTransformerDoesntThrow() { //store values in cache session - .CreateQuery("from Role r left join r.Children left join r.Parent where r.Parent is null") + .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) @@ -157,7 +160,7 @@ public void UsingHqlToFutureWithCacheAndTransformerDoesntThrow() //get values from cache var roles = session - .CreateQuery("from Role r left join r.Children left join r.Parent") + .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) From cfd3bad740a399b42e95fffb50dde3847637c5ac Mon Sep 17 00:00:00 2001 From: Ricardo Peres Date: Thu, 27 Nov 2014 11:42:59 +0000 Subject: [PATCH 5/5] Fixed unit tests --- .../NHSpecificTest/NH3596/CachingWithTransformerTests.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs b/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs index 05841d6f47e..35f3feb2788 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3596/CachingWithTransformerTests.cs @@ -139,7 +139,7 @@ public void UsingQueryOverToFutureWithCacheAndTransformerDoesntThrow() var result = roles.ToList(); - Assert.AreEqual(5, result.Count); + Assert.AreEqual(3, result.Count); } } @@ -168,8 +168,7 @@ public void UsingHqlToFutureWithCacheAndTransformerDoesntThrow() var result = roles.ToList(); - //doesn't work - Assert.AreEqual(5, result.Count); + Assert.AreEqual(3, result.Count); } } }