Skip to content

Commit 06d17c7

Browse files
committed
NH-3845 - Partially fix OfType operator
1 parent b12486e commit 06d17c7

File tree

3 files changed

+39
-31
lines changed

3 files changed

+39
-31
lines changed

src/NHibernate.Test/Linq/WhereTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,14 @@ where o is Mammal
662662
Assert.That(query.Count, Is.EqualTo(3));
663663
}
664664

665+
[Test(Description = "NH-3845")]
666+
public void PolymorphicSearchOnObjectTypeWithOfType()
667+
{
668+
var query = session.Query<Animal>().OfType<Mammal>().ToList();
669+
670+
Assert.That(query.Count, Is.EqualTo(3));
671+
}
672+
665673
[Test]
666674
public void BitwiseQuery()
667675
{

src/NHibernate/Linq/Visitors/HqlGeneratorExpressionTreeVisitor.cs

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -147,34 +147,40 @@ protected HqlTreeNode VisitExpression(Expression expression)
147147

148148
private HqlTreeNode VisitTypeBinaryExpression(TypeBinaryExpression expression)
149149
{
150-
var meta = SessionFactory.GetClassMetadata(expression.TypeOperand) as Persister.Entity.AbstractEntityPersister;
150+
return BuildOfType(expression.Expression, expression.TypeOperand);
151+
}
152+
153+
internal HqlBooleanExpression BuildOfType(Expression expression, System.Type type)
154+
{
155+
var sessionFactory = _parameters.SessionFactory;
156+
var meta = sessionFactory.GetClassMetadata(type) as Persister.Entity.AbstractEntityPersister;
151157
if (meta != null && !meta.IsExplicitPolymorphism)
152158
{
153159
//Adapted the logic found in SingleTableEntityPersister.DiscriminatorFilterFragment
154-
var Factory = SessionFactory as NHibernate.Engine.ISessionFactoryImplementor;
155-
var nodes = new System.Collections.Generic.List<HqlIdent>();
156-
foreach (var typeName in meta.SubclassClosure)
157-
{
158-
var persister = (NHibernate.Persister.Entity.IQueryable)Factory.GetEntityPersister(typeName);
159-
if (persister.IsAbstract) continue;
160-
nodes.Add(_hqlTreeBuilder.Ident(persister.EntityName));
161-
}
160+
var nodes = meta
161+
.SubclassClosure
162+
.Select(typeName => (NHibernate.Persister.Entity.IQueryable) sessionFactory.GetEntityPersister(typeName))
163+
.Where(persister => !persister.IsAbstract)
164+
.Select(persister => _hqlTreeBuilder.Ident(persister.EntityName))
165+
.ToList();
162166

163167
if (nodes.Count == 1)
164168
{
165169
return _hqlTreeBuilder.Equality(
166-
_hqlTreeBuilder.Dot(Visit(expression.Expression).AsExpression(), _hqlTreeBuilder.Class()),
170+
_hqlTreeBuilder.Dot(Visit(expression).AsExpression(), _hqlTreeBuilder.Class()),
167171
nodes[0]);
168172
}
169-
else if (nodes.Count > 1)
173+
174+
if (nodes.Count > 1)
170175
{
171176
return _hqlTreeBuilder.In(
172-
_hqlTreeBuilder.Dot(
173-
Visit(expression.Expression).AsExpression(),
174-
_hqlTreeBuilder.Class()),
175-
_hqlTreeBuilder.ExpressionSubTreeHolder(nodes.ToArray()));
177+
_hqlTreeBuilder.Dot(
178+
Visit(expression).AsExpression(),
179+
_hqlTreeBuilder.Class()),
180+
_hqlTreeBuilder.ExpressionSubTreeHolder(nodes));
176181
}
177-
else
182+
183+
if (nodes.Count == 0)
178184
{
179185
const string abstractClassWithNoSubclassExceptionMessageTemplate =
180186
@"The class {0} can't be instatiated and does not have mapped subclasses;
@@ -185,9 +191,10 @@ private HqlTreeNode VisitTypeBinaryExpression(TypeBinaryExpression expression)
185191
throw new NotSupportedException(string.Format(abstractClassWithNoSubclassExceptionMessageTemplate, meta.EntityName));
186192
}
187193
}
194+
188195
return _hqlTreeBuilder.Equality(
189-
_hqlTreeBuilder.Dot(Visit(expression.Expression).AsExpression(), _hqlTreeBuilder.Class()),
190-
_hqlTreeBuilder.Ident(expression.TypeOperand.FullName));
196+
_hqlTreeBuilder.Dot(Visit(expression).AsExpression(), _hqlTreeBuilder.Class()),
197+
_hqlTreeBuilder.Ident(type.FullName));
191198
}
192199

193200
protected HqlTreeNode VisitNhStar(NhStarExpression expression)
Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
1-
using System.Linq.Expressions;
2-
using NHibernate.Hql.Ast;
3-
using Remotion.Linq.Clauses.ResultOperators;
1+
using Remotion.Linq.Clauses.ResultOperators;
42

53
namespace NHibernate.Linq.Visitors.ResultOperatorProcessors
64
{
75
public class ProcessOfType : IResultOperatorProcessor<OfTypeResultOperator>
86
{
9-
#region IResultOperatorProcessor<OfTypeResultOperator> Members
10-
117
public void Process(OfTypeResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
128
{
13-
Expression source = queryModelVisitor.Model.SelectClause.GetOutputDataInfo().ItemExpression;
9+
var source = queryModelVisitor.Model.SelectClause.GetOutputDataInfo().ItemExpression;
1410

15-
tree.AddWhereClause(tree.TreeBuilder.Equality(
16-
tree.TreeBuilder.Dot(
17-
HqlGeneratorExpressionTreeVisitor.Visit(source, queryModelVisitor.VisitorParameters).AsExpression(),
18-
tree.TreeBuilder.Class()),
19-
tree.TreeBuilder.Ident(resultOperator.SearchedItemType.FullName)));
20-
}
11+
var expression = new HqlGeneratorExpressionTreeVisitor(queryModelVisitor.VisitorParameters)
12+
.BuildOfType(source, resultOperator.SearchedItemType);
2113

22-
#endregion
14+
tree.AddWhereClause(expression);
15+
}
2316
}
2417
}

0 commit comments

Comments
 (0)