Loop detected in LINQ exception expression

I get an error message:

A loop has been detected in the LINQ expression.

in ToList() when trying to do the following:

 private IEnumerable<int> FilterIdsByClient(IEnumerable<int> entityIds) { entityIds = MyObjectContext.CreateObjectSet<TEntity>() .Where(x => x.ClientId == _clientId) .Where(x => entityIds.Contains(x.Id)) .Select(x => x.Id); return entityIds.ToList(); } 

This, however, throws no exceptions and works great:

 private IEnumerable<int> FilterIdsByClient(IEnumerable<int> entityIds) { entityIds = MyObjectContext.CreateObjectSet<TEntity>() .Where(x => x.ClientId == _clientId) .Where(x => entityIds.Contains(x.Id)) .Select(x => x.Id) .ToList(); return entityIds; } 

(Of course, this is a simplified version).

Does anyone know why this strange behavior happens?

Edit:

This is the stack trace:

  at System.Data.Objects.ELinq.Funcletizer.FuncletizingVisitor.Visit(Expression exp) at System.Data.Objects.ELinq.Funcletizer.Funcletize(Expression expression, Func`1& recompileRequired) at System.Data.Objects.ELinq.Funcletizer.FuncletizingVisitor.InlineExpression(Expression exp) at System.Data.Objects.ELinq.Funcletizer.FuncletizingVisitor.InlineObjectQuery(ObjectQuery inlineQuery, Type expressionType) at System.Data.Objects.ELinq.Funcletizer.FuncletizingVisitor.InlineValue(Expression expression, Boolean recompileOnChange) at System.Data.Objects.ELinq.Funcletizer.FuncletizingVisitor.Visit(Expression exp) at System.Linq.Expressions.EntityExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original) at System.Linq.Expressions.EntityExpressionVisitor.VisitMethodCall(MethodCallExpression m) at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp) at System.Data.Objects.ELinq.Funcletizer.FuncletizingVisitor.Visit(Expression exp) at System.Linq.Expressions.EntityExpressionVisitor.VisitLambda(LambdaExpression lambda) at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp) at System.Data.Objects.ELinq.Funcletizer.FuncletizingVisitor.Visit(Expression exp) at System.Linq.Expressions.EntityExpressionVisitor.VisitUnary(UnaryExpression u) at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp) at System.Data.Objects.ELinq.Funcletizer.FuncletizingVisitor.Visit(Expression exp) at System.Linq.Expressions.EntityExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original) at System.Linq.Expressions.EntityExpressionVisitor.VisitMethodCall(MethodCallExpression m) at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp) at System.Data.Objects.ELinq.Funcletizer.FuncletizingVisitor.Visit(Expression exp) at System.Linq.Expressions.EntityExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original) at System.Linq.Expressions.EntityExpressionVisitor.VisitMethodCall(MethodCallExpression m) at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp) at System.Data.Objects.ELinq.Funcletizer.FuncletizingVisitor.Visit(Expression exp) at System.Data.Objects.ELinq.Funcletizer.Funcletize(Expression expression, Func`1& recompileRequired) at System.Data.Objects.ELinq.ExpressionConverter..ctor(Funcletizer funcletizer, Expression expression) at System.Data.Objects.ELinq.ELinqQueryState.CreateExpressionConverter() at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption) at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at ...FilterIdsByClient... 

Edit2:

IEnumerable<int> entityIds in mind that in this case IEnumerable<int> entityIds is a list that starts with an ajax request and not from somewhere in the request.

+8
c # entity-framework entity-framework-4
source share
4 answers

The behavior seems strange because you are not considering closure semantics correctly. See comments below:

 private IEnumerable<int> FilterIdsByClient(IEnumerable<int> entityIds) { // The variable entityIds points to whatever was passed in: A List, according to the edited question. entityIds = //this is an assignment, changing the referent of entityIds MyObjectContext.CreateObjectSet<TEntity>() .Where(x => x.ClientId == _clientId) .Where(x => entityIds.Contains(x.Id)) //this lambda closes over the variable entityIds .Select(x => x.Id); // The query now has a reference to the *variable* entityIds, not to the object that entityIds pointed to originally. // The value of entityIds has been changed; it now points to the query itself! // The query is therefore operating on itself; this causes the "cycle detected" message. // Because of delayed execution, the query is not executed until the next line of code: return entityIds.ToList(); } 
+9
source share

Why are you assigning your parameter? Why not

 private IEnumerable<int> FilterIdsByClient(IEnumerable<int> entityIds) { return MyObjectContext.CreateObjectSet<TEntity>() .Where(x => x.ClientId == _clientId) .Where(x => entityIds.Contains(x.Id)) .Select(x => x.Id) .ToList(); } 
+6
source share

The answer is to not assign a LINQ query to entityIds . See @Stu's answer for a solution.

+4
source share

Of course there is a cycle. You are using entityIds in the Where Linq Extension method, and this query is being built. Instead of changing the entered IEnumerable, return a new query as follows:

 private IEnumerable<int> FilterIdsByClient(IEnumerable<int> entityIds) { var query = MyObjectContext.CreateObjectSet<TEntity>() .Where(x => x.ClientId == _clientId) .Where(x => entityIds.Contains(x.Id)) .Select(x => x.Id); return query.ToList(); } 
+3
source share

All Articles