Skip to content

Commit 0a28698

Browse files
Emil Tzvetkovbahusoid
Emil Tzvetkov
authored andcommitted
GH-2454 fix ConditionalProjection GetType from outer query
1 parent 07aab2e commit 0a28698

File tree

4 files changed

+252
-3
lines changed

4 files changed

+252
-3
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using NHibernate.Cfg.MappingSchema;
12+
using NHibernate.Criterion;
13+
using NHibernate.Mapping.ByCode;
14+
using NHibernate.SqlCommand;
15+
using NUnit.Framework;
16+
17+
namespace NHibernate.Test.NHSpecificTest.GH2454
18+
{
19+
using System.Threading.Tasks;
20+
[TestFixture]
21+
public class ByCodeFixtureAsync : TestCaseMappingByCode
22+
{
23+
protected override HbmMapping GetMappings()
24+
{
25+
var mapper = new ModelMapper();
26+
27+
mapper.Class<Project>(rc =>
28+
{
29+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
30+
rc.Property(x => x.Name);
31+
});
32+
33+
mapper.Class<Component>(rc =>
34+
{
35+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
36+
rc.Property(x => x.Name);
37+
rc.ManyToOne(x => x.Project, m => { m.Column("ProjectId"); m.NotNullable(true); });
38+
});
39+
40+
mapper.Class<Tag>(rc =>
41+
{
42+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
43+
rc.Property(x => x.Name);
44+
rc.ManyToOne(x => x.Component1, m => { m.Column("Component1Id"); m.NotNullable(true); });
45+
rc.ManyToOne(x => x.Component2, m => { m.Column("Component2Id"); m.NotNullable(false); });
46+
});
47+
48+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
49+
}
50+
51+
[Test]
52+
public async Task SubqueryCorrelatedThroughConditional()
53+
{
54+
using (var session = OpenSession())
55+
using (var transaction = session.BeginTransaction())
56+
{
57+
// data
58+
{
59+
// alpha entities
60+
var projectAlpha = new Project { Name = "Alpha" };
61+
session.Save(projectAlpha);
62+
63+
var componentAlpha = new Component { Project = projectAlpha, Name = "Thingie" };
64+
session.Save(componentAlpha);
65+
66+
var tagAlpha = new Tag { Component1 = componentAlpha, Name = "A20" };
67+
session.Save(tagAlpha);
68+
69+
// beta entities
70+
var projectBeta = new Project { Name = "Beta" };
71+
session.Save(projectBeta);
72+
73+
var componentBeta = new Component { Project = projectBeta, Name = "Thingie" };
74+
session.Save(componentBeta);
75+
76+
var tagBeta = new Tag { Component1 = componentBeta, Name = "B17" };
77+
session.Save(tagBeta);
78+
}
79+
80+
session.Flush();
81+
82+
// query
83+
{
84+
ICriteria tagCriteria = session.CreateCriteria(typeof(Tag), "t");
85+
tagCriteria.CreateCriteria("Component1", "c1");
86+
tagCriteria.CreateCriteria("Component2", "c2", JoinType.LeftOuterJoin);
87+
88+
IProjection projectNameProjection;
89+
{
90+
// create correlated subquery
91+
var projectCriteria = DetachedCriteria.For(typeof(Project), "p");
92+
93+
var conditionalCorrelationProjection = Projections.Conditional(
94+
Restrictions.IsNotNull(Projections.Property("t.Component2")),
95+
Projections.Property("c2.Project"),
96+
Projections.Property("c1.Project"));
97+
projectCriteria.Add(Restrictions.EqProperty("p.Id", conditionalCorrelationProjection));
98+
99+
projectCriteria.SetProjection(Projections.Property("p.Name"));
100+
101+
projectNameProjection = Projections.SubQuery(projectCriteria);
102+
}
103+
104+
tagCriteria.Add(Restrictions.Eq(projectNameProjection, "Beta"));
105+
tagCriteria.SetProjection(Projections.Property("t.Name"));
106+
107+
// run query
108+
109+
var results = await (tagCriteria.ListAsync());
110+
111+
Assert.That(results, Is.EquivalentTo(new[] { "B17" }));
112+
}
113+
}
114+
}
115+
}
116+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH2454
4+
{
5+
public class Project
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
}
10+
11+
public class Component
12+
{
13+
public virtual Guid Id { get; set; }
14+
public virtual string Name { get; set; }
15+
public virtual Project Project { get; set; }
16+
}
17+
18+
public class Tag
19+
{
20+
public virtual Guid Id { get; set; }
21+
public virtual string Name { get; set; }
22+
public virtual Component Component1 { get; set; }
23+
public virtual Component Component2 { get; set; }
24+
}
25+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using NHibernate.Cfg.MappingSchema;
2+
using NHibernate.Criterion;
3+
using NHibernate.Mapping.ByCode;
4+
using NHibernate.SqlCommand;
5+
using NUnit.Framework;
6+
7+
namespace NHibernate.Test.NHSpecificTest.GH2454
8+
{
9+
[TestFixture]
10+
public class ByCodeFixture : TestCaseMappingByCode
11+
{
12+
protected override HbmMapping GetMappings()
13+
{
14+
var mapper = new ModelMapper();
15+
16+
mapper.Class<Project>(rc =>
17+
{
18+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
19+
rc.Property(x => x.Name);
20+
});
21+
22+
mapper.Class<Component>(rc =>
23+
{
24+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
25+
rc.Property(x => x.Name);
26+
rc.ManyToOne(x => x.Project, m => { m.Column("ProjectId"); m.NotNullable(true); });
27+
});
28+
29+
mapper.Class<Tag>(rc =>
30+
{
31+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
32+
rc.Property(x => x.Name);
33+
rc.ManyToOne(x => x.Component1, m => { m.Column("Component1Id"); m.NotNullable(true); });
34+
rc.ManyToOne(x => x.Component2, m => { m.Column("Component2Id"); m.NotNullable(false); });
35+
});
36+
37+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
38+
}
39+
40+
[Test]
41+
public void SubqueryCorrelatedThroughConditional()
42+
{
43+
using (var session = OpenSession())
44+
using (var transaction = session.BeginTransaction())
45+
{
46+
// data
47+
{
48+
// alpha entities
49+
var projectAlpha = new Project { Name = "Alpha" };
50+
session.Save(projectAlpha);
51+
52+
var componentAlpha = new Component { Project = projectAlpha, Name = "Thingie" };
53+
session.Save(componentAlpha);
54+
55+
var tagAlpha = new Tag { Component1 = componentAlpha, Name = "A20" };
56+
session.Save(tagAlpha);
57+
58+
// beta entities
59+
var projectBeta = new Project { Name = "Beta" };
60+
session.Save(projectBeta);
61+
62+
var componentBeta = new Component { Project = projectBeta, Name = "Thingie" };
63+
session.Save(componentBeta);
64+
65+
var tagBeta = new Tag { Component1 = componentBeta, Name = "B17" };
66+
session.Save(tagBeta);
67+
}
68+
69+
session.Flush();
70+
71+
// query
72+
{
73+
ICriteria tagCriteria = session.CreateCriteria(typeof(Tag), "t");
74+
tagCriteria.CreateCriteria("Component1", "c1");
75+
tagCriteria.CreateCriteria("Component2", "c2", JoinType.LeftOuterJoin);
76+
77+
IProjection projectNameProjection;
78+
{
79+
// create correlated subquery
80+
var projectCriteria = DetachedCriteria.For(typeof(Project), "p");
81+
82+
var conditionalCorrelationProjection = Projections.Conditional(
83+
Restrictions.IsNotNull(Projections.Property("t.Component2")),
84+
Projections.Property("c2.Project"),
85+
Projections.Property("c1.Project"));
86+
projectCriteria.Add(Restrictions.EqProperty("p.Id", conditionalCorrelationProjection));
87+
88+
projectCriteria.SetProjection(Projections.Property("p.Name"));
89+
90+
projectNameProjection = Projections.SubQuery(projectCriteria);
91+
}
92+
93+
tagCriteria.Add(Restrictions.Eq(projectNameProjection, "Beta"));
94+
tagCriteria.SetProjection(Projections.Property("t.Name"));
95+
96+
// run query
97+
98+
var results = tagCriteria.List();
99+
100+
Assert.That(results, Is.EquivalentTo(new[] { "B17" }));
101+
}
102+
}
103+
}
104+
}
105+
}

src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -804,10 +804,13 @@ public IType GetTypeUsingProjection(ICriteria subcriteria, string propertyName)
804804

805805
public IType GetType(ICriteria subcriteria, string propertyName)
806806
{
807-
if(!TryParseCriteriaPath(subcriteria, propertyName, out var entityName, out var entityPropName, out _))
808-
throw new QueryException("Could not find property " + propertyName);
807+
if (TryGetType(subcriteria, propertyName, out var resultType))
808+
return resultType;
809+
810+
if (outerQueryTranslator != null)
811+
return outerQueryTranslator.GetType(subcriteria, propertyName);
809812

810-
return GetPropertyMapping(entityName).ToType(entityPropName);
813+
throw new QueryException("Could not find property " + propertyName);
811814
}
812815

813816
public bool TryGetType(ICriteria subcriteria, string propertyName, out IType type)

0 commit comments

Comments
 (0)