Skip to content

Commit 6b71ce6

Browse files
authored
Update IIsEntityDecider to use ExpressionsHelper.TryGetMappedType (#2324)
1 parent 329d591 commit 6b71ce6

File tree

7 files changed

+49
-13
lines changed

7 files changed

+49
-13
lines changed

src/NHibernate.DomainModel/Northwind/Entities/Animal.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ public class Animal
1212
public virtual Animal Father { get; set; }
1313
public virtual IList<Animal> Children { get; set; }
1414
public virtual string SerialNumber { get; set; }
15-
}
15+
16+
public virtual Animal FatherOrMother => Father ?? Mother;
17+
}
1618

1719
public abstract class Reptile : Animal
1820
{
@@ -30,4 +32,4 @@ public abstract class Mammal : Animal
3032
public class Dog : Mammal { }
3133

3234
public class Cat : Mammal { }
33-
}
35+
}

src/NHibernate.Test/Async/Linq/SelectionTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,14 @@ public async Task CanSelectFirstElementFromChildCollectionAsync()
289289
}
290290
}
291291

292+
[Test]
293+
public async Task CanSelectNotMappedEntityPropertyAsync()
294+
{
295+
var list = await (db.Animals.Where(o => o.Mother != null).Select(o => o.FatherOrMother.SerialNumber).ToListAsync());
296+
297+
Assert.That(list, Has.Count.GreaterThan(0));
298+
}
299+
292300
[Test]
293301
public async Task CanProjectWithCastAsync()
294302
{

src/NHibernate.Test/Linq/SelectionTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,14 @@ public void CanSelectWrappedType()
328328
Assert.IsTrue(query.ToArray().Length > 0);
329329
}
330330

331+
[Test]
332+
public void CanSelectNotMappedEntityProperty()
333+
{
334+
var list = db.Animals.Where(o => o.Mother != null).Select(o => o.FatherOrMother.SerialNumber).ToList();
335+
336+
Assert.That(list, Has.Count.GreaterThan(0));
337+
}
338+
331339
[Test]
332340
public void CanProjectWithCast()
333341
{

src/NHibernate/Linq/ReWriters/AddJoinsReWriter.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
using System;
22
using System.Collections.Specialized;
33
using System.Linq;
4+
using System.Linq.Expressions;
45
using NHibernate.Engine;
56
using NHibernate.Linq.Clauses;
67
using NHibernate.Linq.Visitors;
8+
using NHibernate.Util;
79
using Remotion.Linq;
810
using Remotion.Linq.Clauses;
911

1012
namespace NHibernate.Linq.ReWriters
1113
{
1214
internal interface IIsEntityDecider
1315
{
14-
bool IsEntity(System.Type type);
15-
bool IsIdentifier(System.Type type, string propertyName);
16+
bool IsEntity(MemberExpression expression, out bool isIdentifier);
1617
}
1718

1819
public class AddJoinsReWriter : NhQueryModelVisitorBase, IIsEntityDecider
@@ -77,11 +78,15 @@ public override void VisitJoinClause(JoinClause joinClause, QueryModel queryMode
7778
_currentJoin = null;
7879
}
7980

81+
// Since v5.3
82+
[Obsolete("This method has no usages and will be removed in a future version")]
8083
public bool IsEntity(System.Type type)
8184
{
8285
return _sessionFactory.GetImplementors(type.FullName).Any();
8386
}
8487

88+
// Since v5.3
89+
[Obsolete("This method has no usages and will be removed in a future version")]
8590
public bool IsIdentifier(System.Type type, string propertyName)
8691
{
8792
var metadata = _sessionFactory.GetClassMetadata(type);
@@ -99,5 +104,14 @@ private void AddJoin(QueryModel queryModel, NhJoinClause joinClause)
99104

100105
queryModel.BodyClauses.Add(joinClause);
101106
}
107+
108+
bool IIsEntityDecider.IsEntity(MemberExpression expression, out bool isIdentifier)
109+
{
110+
isIdentifier =
111+
ExpressionsHelper.TryGetMappedType(_sessionFactory, expression, out var mappedType, out var entityPersister, out _, out var memberPath)
112+
&& entityPersister?.IdentifierPropertyName == memberPath;
113+
114+
return mappedType?.IsEntityType == true;
115+
}
102116
}
103117
}

src/NHibernate/Linq/Visitors/MemberExpressionJoinDetector.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Collections;
22
using System.Collections.Generic;
33
using System.Linq.Expressions;
4+
using NHibernate.Engine;
45
using NHibernate.Linq.Expressions;
56
using NHibernate.Linq.ReWriters;
67
using Remotion.Linq.Clauses;
@@ -39,7 +40,7 @@ protected override Expression VisitMember(MemberExpression expression)
3940
return base.VisitMember(expression);
4041
}
4142

42-
var isIdentifier = _isEntityDecider.IsIdentifier(expression.Expression.Type, expression.Member.Name);
43+
var isEntity = _isEntityDecider.IsEntity(expression, out var isIdentifier);
4344
if (isIdentifier)
4445
_hasIdentifier = true;
4546
if (!isIdentifier)
@@ -50,7 +51,7 @@ protected override Expression VisitMember(MemberExpression expression)
5051
if (!isIdentifier)
5152
_memberExpressionDepth--;
5253

53-
if (_isEntityDecider.IsEntity(expression.Type) &&
54+
if (isEntity &&
5455
((_requiresJoinForNonIdentifier && !_hasIdentifier) || _memberExpressionDepth > 0) &&
5556
_joiner.CanAddJoin(expression))
5657
{

src/NHibernate/Linq/Visitors/SelectClauseNominator.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq.Expressions;
4+
using NHibernate.Engine;
45
using NHibernate.Linq.Functions;
56
using NHibernate.Linq.Expressions;
67
using NHibernate.Util;
@@ -15,6 +16,7 @@ namespace NHibernate.Linq.Visitors
1516
class SelectClauseHqlNominator : RelinqExpressionVisitor
1617
{
1718
private readonly ILinqToHqlGeneratorsRegistry _functionRegistry;
19+
private readonly ISessionFactoryImplementor _sessionFactory;
1820

1921
/// <summary>
2022
/// The expression parts that can be converted to pure HQL.
@@ -35,6 +37,7 @@ class SelectClauseHqlNominator : RelinqExpressionVisitor
3537
public SelectClauseHqlNominator(VisitorParameters parameters)
3638
{
3739
_functionRegistry = parameters.SessionFactory.Settings.LinqToHqlGeneratorsRegistry;
40+
_sessionFactory = parameters.SessionFactory;
3841
}
3942

4043
internal Expression Nominate(Expression expression)
@@ -168,8 +171,10 @@ private bool CanBeEvaluatedInHqlSelectStatement(Expression expression, bool proj
168171
return projectConstantsInHql;
169172
}
170173

171-
// Assume all is good
172-
return true;
174+
return !(expression is MemberExpression memberExpression) || // Assume all is good
175+
// Nominate only expressions that represent a mapped property or a translatable method call
176+
ExpressionsHelper.TryGetMappedType(_sessionFactory, expression, out _, out _, out _, out _) ||
177+
_functionRegistry.TryGetGenerator(memberExpression.Member, out _);
173178
}
174179

175180
private static bool CanBeEvaluatedInHqlStatementShortcut(Expression expression)

src/NHibernate/Linq/Visitors/WhereJoinDetector.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Linq.Expressions;
5+
using NHibernate.Engine;
56
using NHibernate.Linq.ReWriters;
67
using Remotion.Linq.Clauses;
78
using Remotion.Linq.Clauses.Expressions;
@@ -314,10 +315,7 @@ protected override Expression VisitMember(MemberExpression expression)
314315
return base.VisitMember(expression);
315316
}
316317

317-
var isIdentifier = _isEntityDecider.IsIdentifier(
318-
expression.Expression.Type,
319-
expression.Member.Name);
320-
318+
var isEntity = _isEntityDecider.IsEntity(expression, out var isIdentifier);
321319
if (!isIdentifier)
322320
_memberExpressionDepth++;
323321

@@ -327,7 +325,7 @@ protected override Expression VisitMember(MemberExpression expression)
327325
_memberExpressionDepth--;
328326

329327
ExpressionValues values = _values.Pop().Operation(pvs => pvs.MemberAccess(expression.Type));
330-
if (_isEntityDecider.IsEntity(expression.Type))
328+
if (isEntity)
331329
{
332330
// Don't add joins for things like a.B == a.C where B and C are entities.
333331
// We only need to join B when there's something like a.B.D.

0 commit comments

Comments
 (0)