-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Refreshing Db Context single entity with ReloadAsync after using raw SQL to delete data results with strange behavior #15645
Comments
Note for triage--repro below. The issue here is that when the refreshed entity is detached we do not fix-up navigation properties to it. I think this was originally by-design, but we have since revised fix-up behaviors in this area and I think it makes sense to fixup the references from tracked entities so that they no longer refer to the detached entities. This is technically a breaking change. public class Menu
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required]
[MaxLength(64)]
public string Name { get; set; }
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public virtual Menu Parent { get; set; }
public virtual List<Menu> Items { get; set; }
}
public class BloggingContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0");
}
public DbSet<Menu> Menus { get; set; }
}
public class Program
{
public static async Task Main()
{
using (var context = new BloggingContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
context.AddRange(
new Menu
{
Id = 1,
Name = "RootMenuItem 1",
Items = new List<Menu>
{
new Menu
{
Id = 2,
Name = "ChildItem_To_Delete"
}
}
});
context.SaveChanges();
}
using (var context = new BloggingContext())
{
var menuItems = await context.Menus.Include(x => x.Items).ToAsyncEnumerable().ToList();
var toDelete = menuItems.Single(e => e.Id == 2);
await context.Database.ExecuteSqlCommandAsync($"Delete from Menus where Id = 2");
await context.Entry(toDelete).ReloadAsync();
var deletedEntityExistence = menuItems.First(x => x.Id == 1)
.Items.FirstOrDefault(x => x.Id == 2);
if (deletedEntityExistence != null)
throw new Exception("Strange behaviour!!!");
}
}
} |
Note: also check this scenario for owned entities. |
…t dramatically change detach behavior Fixes #17784 In 3.0 we made a [simple change](7e65b82#diff-7767de8ee880eb46efbfc9d2153dd33a) for #15645 that started clearing navigation properties when they referenced detached entities. In retrospect this was the wrong thing to do as people are relying on this to be able to detach all entities from the context. The new fix restores the pre-3.0 detach behavior, and sends the reload of a deleted entity through a simulated to delete instead.
…t dramatically change detach behavior Fixes #17784 In 3.0 we made a [simple change](7e65b82#diff-7767de8ee880eb46efbfc9d2153dd33a) for #15645 that started clearing navigation properties when they referenced detached entities. In retrospect this was the wrong thing to do as people are relying on this to be able to detach all entities from the context. The new fix restores the pre-3.0 detach behavior, and sends the reload of a deleted entity through a simulated to delete instead.
I'm facing a strange behavior when I try to refresh single entity form Db Context using
.ReloadAsync
for tracked entity.Simply after deleting the single entity using raw SQL and forcing EF to reload changes form DB is not enough to delete the entity from the cache. I have read couple of issues that may be related to this one but I want to have an explanation for this kind of behavior because it is really strange.
Explanation of the problem
I have self-referenced domain model named Menu which looks like:
Steps to reproduce
RootMenuItem 1 :
RootMenuItem 2 :
Because it is self-referenced table, the functionality for menu deletion (recursively) is done with stored procedure on database level because of performance.
Here I will provide the simpler example just to point the strange behavior.
Lets say I want to delete the ChildItem_To_Delete item that belongs to RootMenuItem 1 and has no children.
Deletion of Menu entity and strange behavior occurs
Here I will provide a piece of code with enough comments that I believe will explain the behavior and expectations.
After deletion of ChildItem_To_Delete there are 7 menu items in the database left but when I use the last query with
.Include
, returned RootMenuItem 1 still has 3 children including the deleted item.I know that after using raw SQL, DB Context may be outdated and we need to reload all entities that we want to make Db Context aware for changes, but why some queries are returning the expected result and some are not (as
.Include
)?After this example I think even
.ReloadAsync
of tracked entry is not working as expected.Please correct me If I'm wrong.
Further technical details
EF Core version: 2.1.2
Database Provider: Microsoft.EntityFrameworkCore.SqlServer (V2.1.2)
Operating system: Windows 10 x64
The text was updated successfully, but these errors were encountered: