Skip to content

Commit 7691115

Browse files
committed
Replace TryGetAllMemberMetadata with a visitor class
1 parent 8187593 commit 7691115

File tree

1 file changed

+96
-76
lines changed

1 file changed

+96
-76
lines changed

src/NHibernate/Util/ExpressionsHelper.cs

Lines changed: 96 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using NHibernate.Linq;
88
using NHibernate.Linq.Expressions;
99
using NHibernate.Linq.Functions;
10+
using NHibernate.Linq.Visitors;
1011
using NHibernate.Persister.Collection;
1112
using NHibernate.Persister.Entity;
1213
using 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

Comments
 (0)