I get the error :
A cycle was detected in a LINQ expression.
in ToList()
while 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 doesn't throw any exception and works fine:
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;
}
(This is a simplfied version of course).
Anyone have a clue 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:
Should note that in this case, IEnumerable<int> entityIds
is a list comming from an ajax request and not a query from somewhere.
The behavior seems strange because you are not considering the closure semantics correctly. See the 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();
}
Why are you assigning to 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();
}
The answer is to not assign the LINQ query to entityIds
. See @Stu's answer for a solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With