Legion
Legion

Reputation: 3427

Foreach loop doesn't iterate over entire IEnumerable

My foreach loop is not iterating over the entire collection, just the first element and I can't figure out why. The only similar question I found was this one: IEnumerable not enumerating in foreach

But the only answer was posted by the question author and he talks about IEnumerable having a timeout which doesn't really make sense to me and I've never heard of before.

IEnumerable<Document> documentsToAdd = dbEvent.Documents.Where(
    dbd => !eventToSave.Documents.Select(d => d.DocumentId)
    .Contains(dbd.DocumentId));
foreach (Document documentToAdd in documentsToAdd) {
    documentToAdd.DocumentType = null;
    documentToAdd.DeletedByUser = null;
    documentToAdd.DocumentOwnerTeam = null;
    documentToAdd.UploadedByUser = null;
    documentToAdd.UploadedInStage = null;
    hcDbContext.Documents.Add(documentToAdd);
}

In the debugger I can see that documentsToAdd has 3 elements in the collection. But when I step through the loop it only goes through once and then moves on, so only the first document is saved. Since I've verified the contents of documentsToAdd, I know the problem isn't in the Where clause. Why won't foreach go through the entire collection?

EDIT

To be clear, no exception is thrown. It goes through the loop once and then moves on to the next line after the foreach.

Upvotes: 1

Views: 2190

Answers (1)

user1023602
user1023602

Reputation:

An IEnumerable is an iterator, so it returns one result at a time.

Each time foreach loops, it asks the iterator for the next result. Sometimes results can disappear from the collection being enumerated, so you get unexpected behaviour.

To avoid this, make sure you have all the results before starting the foreach, by calling .ToList()

  // Make a list of all documents
  List<Document> documentsToAdd;

  documentsToAdd = dbEvent.Documents
                          .Where(dbd => !eventToSave.Documents
                                                    .Select(d => d.DocumentId)
                                                    .Contains(dbd.DocumentId))
                          .ToList();   // load all results

  // Now this will loop through the whole list
  foreach (Document documentToAdd in documentsToAdd) 
  {
      documentToAdd.DocumentType = null;
      documentToAdd.DeletedByUser = null;
      documentToAdd.DocumentOwnerTeam = null;
      documentToAdd.UploadedByUser = null;
      documentToAdd.UploadedInStage = null;

      hcDbContext.Documents.Add(documentToAdd);
  }

Upvotes: 2

Related Questions