I get the error :
A cycle was detected in a LINQ expression.
in ToList()
while trying to do the following:
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.
Of course there is a cycle. You are using entityIds in the Where Linq Extension method and it is the query being constructed itself. Instead of modifying the inputted 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();
}