diff --git a/src/EFCore/ChangeTracking/LocalView.cs b/src/EFCore/ChangeTracking/LocalView.cs index a84f3010442..9009b863ea8 100644 --- a/src/EFCore/ChangeTracking/LocalView.cs +++ b/src/EFCore/ChangeTracking/LocalView.cs @@ -317,8 +317,7 @@ public virtual void CopyTo(TEntity[] array, int arrayIndex) public virtual bool Remove(TEntity item) { var entry = _context.GetDependencies().StateManager.TryGetEntry(item); - if (entry != null - && entry.EntityState != EntityState.Deleted) + if (entry is { EntityState: not EntityState.Deleted and not EntityState.Detached }) { try { diff --git a/test/EFCore.Specification.Tests/DataBindingTestBase.cs b/test/EFCore.Specification.Tests/DataBindingTestBase.cs index 752b7ff2816..118c6b500af 100644 --- a/test/EFCore.Specification.Tests/DataBindingTestBase.cs +++ b/test/EFCore.Specification.Tests/DataBindingTestBase.cs @@ -237,6 +237,78 @@ public virtual void Entities_with_state_changed_to_deleted_are_removed_from_loca Assert.Equal(TotalCount - UnchangedCount, local.Count); } + [ConditionalTheory] + [InlineData(false)] + [InlineData(true)] // Issue #35243 + public virtual void Remove_detached_entity_from_LocalView(bool toObservableCollection) + { + using var context = CreateF1Context(); + var localView = context.Drivers.Local; + var local = toObservableCollection + ? (ICollection)localView.ToObservableCollection() + : localView; + + Assert.Equal(0, local.Count); + + var driver1 = new Driver + { + Id = -1, + Name = "Larry David", + TeamId = Team.Ferrari, + CarNumber = 13 + }; + + var driver2 = new Driver + { + Id = -2, + Name = "Jerry Seinfeld", + TeamId = Team.Mercedes, + CarNumber = 14 + }; + + var driver3 = new Driver + { + Id = -3, + Name = "George Costanza", + TeamId = Team.McLaren, + CarNumber = 15 + }; + + local.Add(driver1); + local.Add(driver2); + + Assert.Equal(2, local.Count); + Assert.Equal(2, local.ToList().Count); + + Assert.True(local.Contains(driver1)); + Assert.True(localView.Contains(driver1)); + Assert.True(local.Contains(driver2)); + Assert.True(localView.Contains(driver2)); + Assert.False(local.Contains(driver3)); + Assert.False(localView.Contains(driver3)); + + context.Entry(driver3); + + Assert.True(local.Contains(driver1)); + Assert.True(localView.Contains(driver1)); + Assert.True(local.Contains(driver2)); + Assert.True(localView.Contains(driver2)); + Assert.False(local.Contains(driver3)); + Assert.False(localView.Contains(driver3)); + + local.Remove(driver3); + + Assert.Equal(2, local.Count); + Assert.Equal(2, local.ToList().Count); + + Assert.True(local.Contains(driver1)); + Assert.True(localView.Contains(driver1)); + Assert.True(local.Contains(driver2)); + Assert.True(localView.Contains(driver2)); + Assert.False(local.Contains(driver3)); + Assert.False(localView.Contains(driver3)); + } + [ConditionalTheory] [InlineData(false)] [InlineData(true)]