1
+ using System . Collections ;
2
+ using System . Collections . Generic ;
3
+ using System . Linq . Expressions ;
4
+ using NHibernate . Linq . ReWriters ;
5
+ using Remotion . Linq . Clauses ;
6
+ using Remotion . Linq . Clauses . Expressions ;
7
+ using Remotion . Linq . Parsing ;
8
+
9
+ namespace NHibernate . Linq . Visitors
10
+ {
11
+ /// <summary>
12
+ /// Detects joins in Select, OrderBy and Results (GroupBy) clauses.
13
+ /// Replaces them with appropriate joins, maintaining reference equality between different clauses.
14
+ /// This allows extracted GroupBy key expression to also be replaced so that they can continue to match replaced Select expressions
15
+ /// </summary>
16
+ internal class MemberExpressionJoinDetector : ExpressionTreeVisitor
17
+ {
18
+ private readonly IIsEntityDecider _isEntityDecider ;
19
+ private readonly IJoiner _joiner ;
20
+
21
+ private bool _requiresJoinForNonIdentifier ;
22
+ private bool _hasIdentifier ;
23
+ private int _memberExpressionDepth ;
24
+
25
+ public MemberExpressionJoinDetector ( IIsEntityDecider isEntityDecider , IJoiner joiner )
26
+ {
27
+ _isEntityDecider = isEntityDecider ;
28
+ _joiner = joiner ;
29
+ }
30
+
31
+ protected override Expression VisitMemberExpression ( MemberExpression expression )
32
+ {
33
+ var isIdentifier = _isEntityDecider . IsIdentifier ( expression . Expression . Type , expression . Member . Name ) ;
34
+ if ( isIdentifier )
35
+ _hasIdentifier = true ;
36
+ if ( ! isIdentifier )
37
+ _memberExpressionDepth ++ ;
38
+
39
+ var result = base . VisitMemberExpression ( expression ) ;
40
+
41
+ if ( ! isIdentifier )
42
+ _memberExpressionDepth -- ;
43
+
44
+ if ( _isEntityDecider . IsEntity ( expression . Type ) &&
45
+ ( ( _requiresJoinForNonIdentifier && ! _hasIdentifier ) || _memberExpressionDepth > 0 ) &&
46
+ _joiner . CanAddJoin ( expression ) )
47
+ {
48
+ var key = ExpressionKeyVisitor . Visit ( expression , null ) ;
49
+ return _joiner . AddJoin ( result , key ) ;
50
+ }
51
+
52
+ return result ;
53
+ }
54
+
55
+ protected override Expression VisitSubQueryExpression ( SubQueryExpression expression )
56
+ {
57
+ expression . QueryModel . TransformExpressions ( VisitExpression ) ;
58
+ return expression ;
59
+ }
60
+
61
+ protected override Expression VisitConditionalExpression ( ConditionalExpression expression )
62
+ {
63
+ var oldRequiresJoinForNonIdentifier = _requiresJoinForNonIdentifier ;
64
+ _requiresJoinForNonIdentifier = false ;
65
+ var newTest = VisitExpression ( expression . Test ) ;
66
+ _requiresJoinForNonIdentifier = oldRequiresJoinForNonIdentifier ;
67
+ var newFalse = VisitExpression ( expression . IfFalse ) ;
68
+ var newTrue = VisitExpression ( expression . IfTrue ) ;
69
+ if ( ( newTest != expression . Test ) || ( newFalse != expression . IfFalse ) || ( newTrue != expression . IfTrue ) )
70
+ return Expression . Condition ( newTest , newTrue , newFalse ) ;
71
+ return expression ;
72
+ }
73
+
74
+ public void Transform ( SelectClause selectClause )
75
+ {
76
+ _requiresJoinForNonIdentifier = true ;
77
+ selectClause . TransformExpressions ( VisitExpression ) ;
78
+ _requiresJoinForNonIdentifier = false ;
79
+ }
80
+
81
+ public void Transform ( ResultOperatorBase resultOperator )
82
+ {
83
+ resultOperator . TransformExpressions ( VisitExpression ) ;
84
+ }
85
+
86
+ public void Transform ( Ordering ordering )
87
+ {
88
+ ordering . TransformExpressions ( VisitExpression ) ;
89
+ }
90
+ }
91
+ }
0 commit comments