Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent Collection was modified; enumeration operation may not execute. #8959

Merged
merged 1 commit into from
Jun 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/EFCore/ChangeTracking/Internal/NavigationFixer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ private void InitialFixup(
{
if (principalToDependent.IsCollection())
{
var dependents = ((IEnumerable)navigationValue).Cast<object>();
var dependents = ((IEnumerable)navigationValue).Cast<object>().ToList();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using ArrayList here to avoid allocating during Cast.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ArrayList requires an ICollection, but we only have an IEnumerable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typical!

foreach (var dependentEntity in dependents)
{
var dependentEntry = stateManager.TryGetEntry(dependentEntity);
Expand Down
50 changes: 50 additions & 0 deletions test/EFCore.Tests/ChangeTracking/Internal/NavigationFixerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,56 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking.Internal
{
public class NavigationFixerTest
{
[Fact]
public void Does_not_throw_if_Add_during_fixup()
{
using (var context = new FixupContext())
{
var blog1 = new Blog { Id = 1 };
var blog2 = new Blog { Id = 2 };

var post1 = context.Add(new Post { BlogId = 2 }).Entity;

blog1.Posts.Add(post1);
blog1.Posts.Add(new Post { BlogId = 2 });

context.Add(blog2);
context.Add(blog1);
}
}

private class FixupContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }

protected internal override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseInMemoryDatabase(typeof(FixupContext).FullName);
}

private class Blog
{
public int Id { get; set; }
public HashSet<Post> Posts { get; } = new HashSet<Post>();
}

private class Post
{
private Blog _blog;
public int Id { get; set; }
public int BlogId { get; set; }

public Blog Blog
{
get => _blog;
set
{
_blog = value;
_blog.Posts.Add(new Post());
}
}
}

[Fact]
public void Does_fixup_of_related_principals()
{
Expand Down