33using System . Collections . ObjectModel ;
44using System . Linq . Expressions ;
55using NHibernate . Linq . Visitors ;
6+ using Remotion . Linq ;
67using Remotion . Linq . Clauses ;
78using Remotion . Linq . Clauses . Expressions ;
89
910namespace NHibernate . Linq . Clauses
1011{
1112 /// <summary>
12- /// All joins are created as outer joins. An optimization in <see cref="WhereJoinDetector"/> finds
13- /// joins that may be inner joined and calls <see cref="MakeInner"/> on them.
14- /// <see cref="QueryModelVisitor"/>'s <see cref="QueryModelVisitor.VisitAdditionalFromClause" /> will
15- /// then emit the correct HQL join.
13+ /// All joins are created as outer joins. An optimization in <see cref="WhereJoinDetector" /> finds
14+ /// joins that may be inner joined and calls <see cref="MakeInner" /> on them.
15+ /// <see cref="QueryModelVisitor" />'s <see cref="QueryModelVisitor.VisitNhJoinClause" /> will
16+ /// then emit the correct HQL join.
1617 /// </summary>
17- public class NhJoinClause : AdditionalFromClause
18+ public class NhJoinClause : NhClauseBase , IFromClause , IBodyClause
1819 {
20+ Expression _fromExpression ;
21+ string _itemName ;
22+ System . Type _itemType ;
23+
1924 public NhJoinClause ( string itemName , System . Type itemType , Expression fromExpression )
2025 : this ( itemName , itemType , fromExpression , new NhWithClause [ 0 ] )
2126 {
2227 }
2328
29+ /// <summary>
30+ /// Initializes a new instance of the <see cref="T:NHibernate.Linq.Clauses.NhJoinClause" /> class.
31+ /// </summary>
32+ /// <param name="itemName">A name describing the items generated by the from clause.</param>
33+ /// <param name="itemType">The type of the items generated by the from clause.</param>
34+ /// <param name="fromExpression">
35+ /// The <see cref="T:System.Linq.Expressions.Expression" /> generating data items for this
36+ /// from clause.
37+ /// </param>
38+ /// <param name="restrictions"></param>
2439 public NhJoinClause ( string itemName , System . Type itemType , Expression fromExpression , IEnumerable < NhWithClause > restrictions )
25- : base ( itemName , itemType , fromExpression )
2640 {
27- Restrictions = new ObservableCollection < NhWithClause > ( ) ;
28- foreach ( var withClause in restrictions )
29- Restrictions . Add ( withClause ) ;
41+ if ( string . IsNullOrEmpty ( itemName ) ) throw new ArgumentException ( "Value cannot be null or empty." , nameof ( itemName ) ) ;
42+ if ( itemType == null ) throw new ArgumentNullException ( nameof ( itemType ) ) ;
43+ if ( fromExpression == null ) throw new ArgumentNullException ( nameof ( fromExpression ) ) ;
44+
45+ _itemName = itemName ;
46+ _itemType = itemType ;
47+ _fromExpression = fromExpression ;
48+
49+ Restrictions = new ObservableCollection < NhWithClause > ( restrictions ) ;
3050 IsInner = false ;
3151 }
3252
33- public ObservableCollection < NhWithClause > Restrictions { get ; private set ; }
53+ public ObservableCollection < NhWithClause > Restrictions { get ; }
3454
3555 public bool IsInner { get ; private set ; }
3656
37- public override AdditionalFromClause Clone ( CloneContext cloneContext )
57+ public void TransformExpressions ( Func < Expression , Expression > transformation )
3858 {
39- var joinClause = new NhJoinClause ( ItemName , ItemType , FromExpression ) ;
59+ if ( transformation == null ) throw new ArgumentNullException ( nameof ( transformation ) ) ;
4060 foreach ( var withClause in Restrictions )
61+ withClause . TransformExpressions ( transformation ) ;
62+ FromExpression = transformation ( FromExpression ) ;
63+ }
64+
65+ /// <summary>
66+ /// Accepts the specified visitor by calling its
67+ /// <see
68+ /// cref="M:Remotion.Linq.IQueryModelVisitor.VisitNhJoinClause(NHibernate.Linq.Clauses.NhJoinClause,Remotion.Linq.QueryModel,System.Int32)" />
69+ /// method.
70+ /// </summary>
71+ /// <param name="visitor">The visitor to accept.</param>
72+ /// <param name="queryModel">The query model in whose context this clause is visited.</param>
73+ /// <param name="index">
74+ /// The index of this clause in the <paramref name="queryModel" />'s
75+ /// <see cref="P:Remotion.Linq.QueryModel.BodyClauses" /> collection.
76+ /// </param>
77+ protected override void Accept ( INhQueryModelVisitor visitor , QueryModel queryModel , int index )
78+ {
79+ visitor . VisitNhJoinClause ( this , queryModel , index ) ;
80+ }
81+
82+ IBodyClause IBodyClause . Clone ( CloneContext cloneContext )
83+ {
84+ return Clone ( cloneContext ) ;
85+ }
86+
87+ /// <summary>
88+ /// Gets or sets a name describing the items generated by this from clause.
89+ /// </summary>
90+ /// <remarks>
91+ /// Item names are inferred when a query expression is parsed, and they usually correspond to the variable names
92+ /// present in that expression.
93+ /// However, note that names are not necessarily unique within a <see cref="T:Remotion.Linq.QueryModel" />. Use names
94+ /// only for readability and debugging, not for
95+ /// uniquely identifying <see cref="T:Remotion.Linq.Clauses.IQuerySource" /> objects. To match an
96+ /// <see cref="T:Remotion.Linq.Clauses.IQuerySource" /> with its references, use the
97+ /// <see cref="P:Remotion.Linq.Clauses.Expressions.QuerySourceReferenceExpression.ReferencedQuerySource" /> property
98+ /// rather than the <see cref="P:NHibernate.Linq.Clauses.NhJoinClause.ItemName" />.
99+ /// </remarks>
100+ public string ItemName
101+ {
102+ get { return _itemName ; }
103+ set
104+ {
105+ if ( string . IsNullOrEmpty ( value ) ) throw new ArgumentException ( "Value cannot be null or empty." , nameof ( value ) ) ;
106+ _itemName = value ;
107+ }
108+ }
109+
110+ /// <summary>
111+ /// Gets or sets the type of the items generated by this from clause.
112+ /// </summary>
113+ /// <note type="warning">
114+ /// Changing the <see cref="P:NHibernate.Linq.Clauses.NhJoinClause.ItemType" /> of a
115+ /// <see cref="T:Remotion.Linq.Clauses.IQuerySource" /> can make all
116+ /// <see cref="T:Remotion.Linq.Clauses.Expressions.QuerySourceReferenceExpression" /> objects that
117+ /// point to that <see cref="T:Remotion.Linq.Clauses.IQuerySource" /> invalid, so the property setter should be used
118+ /// with care.
119+ /// </note>
120+ public System . Type ItemType
121+ {
122+ get { return _itemType ; }
123+ set
41124 {
42- var withClause2 = new NhWithClause ( withClause . Predicate ) ;
43- joinClause . Restrictions . Add ( withClause2 ) ;
125+ if ( value == null ) throw new ArgumentNullException ( nameof ( value ) ) ;
126+ _itemType = value ;
44127 }
128+ }
45129
130+ /// <summary>
131+ /// The expression generating the data items for this from clause.
132+ /// </summary>
133+ public Expression FromExpression
134+ {
135+ get { return _fromExpression ; }
136+ set
137+ {
138+ if ( value == null ) throw new ArgumentNullException ( nameof ( value ) ) ;
139+ _fromExpression = value ;
140+ }
141+ }
142+
143+ public void CopyFromSource ( IFromClause source )
144+ {
145+ if ( source == null ) throw new ArgumentNullException ( nameof ( source ) ) ;
146+ FromExpression = source . FromExpression ;
147+ ItemName = source . ItemName ;
148+ ItemType = source . ItemType ;
149+ }
150+
151+ public NhJoinClause Clone ( CloneContext cloneContext )
152+ {
153+ var joinClause = new NhJoinClause ( ItemName , ItemType , FromExpression , Restrictions ) ;
46154 cloneContext . QuerySourceMapping . AddMapping ( this , new QuerySourceReferenceExpression ( joinClause ) ) ;
47- return base . Clone ( cloneContext ) ;
155+ return joinClause ;
48156 }
49157
50158 public void MakeInner ( )
51159 {
52160 IsInner = true ;
53161 }
54162
55- public override void TransformExpressions ( Func < Expression , Expression > transformation )
163+ public override string ToString ( )
56164 {
57- foreach ( var withClause in Restrictions )
58- withClause . TransformExpressions ( transformation ) ;
59- base . TransformExpressions ( transformation ) ;
165+ return string . Format ( "join {0} {1} in {2}" , ItemType . Name , ItemName , FromExpression ) ;
60166 }
61167 }
62- }
168+ }
0 commit comments