77using NHibernate . Linq ;
88using NHibernate . Linq . Expressions ;
99using NHibernate . Linq . Functions ;
10+ using NHibernate . Linq . Visitors ;
1011using NHibernate . Persister . Collection ;
1112using NHibernate . Persister . Entity ;
1213using NHibernate . Type ;
@@ -33,7 +34,7 @@ internal static string TryGetEntityName(
3334 out string memberPath ,
3435 out IType memberType )
3536 {
36- var memberPaths = TryGetAllMemberMetadata ( expression , out var entityName , out var convertType ) ;
37+ var memberPaths = MemberMetadataExtractor . TryGetAllMemberMetadata ( expression , out var entityName , out var convertType ) ;
3738 if ( memberPaths == null )
3839 {
3940 memberPath = null ;
@@ -153,81 +154,6 @@ internal static string TryGetEntityName(
153154 }
154155 }
155156
156- private static Stack < MemberMetadata > TryGetAllMemberMetadata (
157- Expression expression ,
158- out string entityName ,
159- out System . Type convertType )
160- {
161- var memberPaths = new Stack < MemberMetadata > ( ) ;
162- var currentExpression = expression ;
163- convertType = null ;
164- bool hasIndexer = false ;
165- while ( true )
166- {
167- if ( currentExpression is MemberExpression subMemberExpression )
168- {
169- memberPaths . Push ( new MemberMetadata ( subMemberExpression . Member . Name , convertType , hasIndexer ) ) ;
170- convertType = null ;
171- hasIndexer = false ;
172- currentExpression = subMemberExpression . Expression ;
173- }
174- else if ( currentExpression is QuerySourceReferenceExpression querySourceReferenceExpression )
175- {
176- if ( querySourceReferenceExpression . ReferencedQuerySource is IFromClause fromClause )
177- {
178- currentExpression = fromClause . FromExpression ;
179- }
180- else if ( querySourceReferenceExpression . ReferencedQuerySource is JoinClause joinClause )
181- {
182- currentExpression = joinClause . InnerSequence ;
183- }
184- else
185- {
186- // Unknown ReferencedQuerySource
187- entityName = null ;
188- return null ;
189- }
190- }
191- else if ( currentExpression is UnaryExpression unaryExpression ) // ((BaseEntity)q.Entity).Prop
192- {
193- currentExpression = unaryExpression . Operand ;
194- convertType = unaryExpression . Type ;
195- }
196- else if ( currentExpression is NhNominatedExpression nominatedExpression ) // ((BaseEntity)q.Entity).Prop
197- {
198- currentExpression = nominatedExpression . Expression ;
199- }
200- else if ( currentExpression is ConstantExpression constantExpression )
201- {
202- if ( ! ( constantExpression . Value is IEntityNameProvider entityNameProvider ) )
203- {
204- // Not a NhQueryable<T>
205- entityName = null ;
206- return null ;
207- }
208-
209- entityName = entityNameProvider . EntityName ;
210- break ;
211- }
212- else if ( currentExpression is MethodCallExpression methodCallExpression &&
213- ListIndexerGenerator . IsMethodSupported ( methodCallExpression . Method ) )
214- {
215- currentExpression = methodCallExpression . Object == null
216- ? Enumerable . First ( methodCallExpression . Arguments ) // q.Children.ElementAt(0)
217- : methodCallExpression . Object ; // q.Children[0]
218- hasIndexer = true ;
219- }
220- else
221- {
222- // Not supported expressions
223- entityName = null ;
224- return null ;
225- }
226- }
227-
228- return memberPaths ;
229- }
230-
231157 private static string GetEntityName (
232158 string currentEntityName ,
233159 System . Type convertedType ,
@@ -330,6 +256,100 @@ private static IType GetType(
330256 return null ;
331257 }
332258
259+ private class MemberMetadataExtractor : NhExpressionVisitor
260+ {
261+ private readonly Stack < MemberMetadata > _memberPaths = new Stack < MemberMetadata > ( ) ;
262+ private System . Type _convertType ;
263+ private bool _hasIndexer ;
264+ private string _entityName ;
265+
266+ public static Stack < MemberMetadata > TryGetAllMemberMetadata (
267+ Expression expression ,
268+ out string entityName ,
269+ out System . Type convertType )
270+ {
271+ var extractor = new MemberMetadataExtractor ( ) ;
272+ extractor . Accept ( expression ) ;
273+ entityName = extractor . _entityName ;
274+ convertType = entityName != null ? extractor . _convertType : null ;
275+ return entityName != null ? extractor . _memberPaths : null ;
276+ }
277+
278+ private void Accept ( Expression expression )
279+ {
280+ base . Visit ( expression ) ;
281+ }
282+
283+ protected override Expression VisitMember ( MemberExpression node )
284+ {
285+ _memberPaths . Push ( new MemberMetadata ( node . Member . Name , _convertType , _hasIndexer ) ) ;
286+ _convertType = null ;
287+ _hasIndexer = false ;
288+ return base . Visit ( node . Expression ) ;
289+ }
290+
291+ protected override Expression VisitQuerySourceReference ( QuerySourceReferenceExpression node )
292+ {
293+ if ( node . ReferencedQuerySource is IFromClause fromClause )
294+ {
295+ return base . Visit ( fromClause . FromExpression ) ;
296+ }
297+
298+ if ( node . ReferencedQuerySource is JoinClause joinClause )
299+ {
300+ return base . Visit ( joinClause . InnerSequence ) ;
301+ }
302+
303+ // Not supported expression
304+ _entityName = null ;
305+ return node ;
306+ }
307+
308+ protected override Expression VisitUnary ( UnaryExpression node )
309+ {
310+ _convertType = node . Type ;
311+ return base . Visit ( node . Operand ) ;
312+ }
313+
314+ protected internal override Expression VisitNhNominated ( NhNominatedExpression node )
315+ {
316+ return base . Visit ( node ) ;
317+ }
318+
319+ protected override Expression VisitConstant ( ConstantExpression node )
320+ {
321+ _entityName = node . Value is IEntityNameProvider entityNameProvider
322+ ? entityNameProvider . EntityName
323+ : null ; // Not a NhQueryable<T>
324+
325+ return node ;
326+ }
327+
328+ protected override Expression VisitMethodCall ( MethodCallExpression node )
329+ {
330+ if ( ListIndexerGenerator . IsMethodSupported ( node . Method ) )
331+ {
332+ _hasIndexer = true ;
333+ return base . Visit (
334+ node . Object == null
335+ ? Enumerable . First ( node . Arguments ) // q.Children.ElementAt(0)
336+ : node . Object // q.Children[0]
337+ ) ;
338+ }
339+
340+ // Not supported expression
341+ _entityName = null ;
342+ return node ;
343+ }
344+
345+ public override Expression Visit ( Expression node )
346+ {
347+ // Not supported expression
348+ _entityName = null ;
349+ return node ;
350+ }
351+ }
352+
333353 private struct MemberMetadata
334354 {
335355 public MemberMetadata ( string path , System . Type convertType , bool hasIndexer )
0 commit comments