Skip to content

Stop fixing up to Deleted entities #28249

@qslcna

Description

@qslcna

By reading this post relationship-changes. In many-to-many relationships, I consider when removing join entities PostTags from post.PostTags the removed entity will also disapper from tag.PostTags

If query tags before ctx.ChangeTracker.DetectChanges() it performs as expected.

However call ctx.ChangeTracker.DetectChanges() before query tags, the tag{id=2}'s navigation property PostTags still has {PostId: 1, TagId: 2} which state is deleted.

It dosen't disapper although I call ctx.ChangeTracker.DetectChanges() again

how to make DetectChanges has consistent result, no matter what order of invocation.

Entitis

using System.Collections.Generic;

namespace Web.Tests
{
    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }

        public IList<PostTag> PostTags { get; } = new List<PostTag>(); // Collection navigation
    }

    public class Tag
    {
        public int Id { get; set; }
        public string Text { get; set; }

        public IList<PostTag> PostTags { get; } = new List<PostTag>(); // Collection navigation
    }

    public class PostTag
    {
        public int PostId { get; set; } // First part of composite PK; FK to Post
        public int TagId { get; set; } // Second part of composite PK; FK to Tag

        public Post Post { get; set; } // Reference navigation
        public Tag Tag { get; set; } // Reference navigation
    }
}
using Microsoft.EntityFrameworkCore;

namespace Web.Tests
{
    public class BlogContext : DbContext
    {
        public BlogContext(DbContextOptions<BlogContext> options) : base(options) { }

        public DbSet<Post> Posts { get; set; }
        public DbSet<Tag> Tags { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Post>()
                .HasData(
                    new Post { Id = 1, Title = "How to use vs?", Content = "blababa" }
                );

            modelBuilder.Entity<Tag>()
                .HasData(
                    new Tag { Id = 1, Text = ".NET" },
                    new Tag { Id = 2, Text = "C#" }

                );
            modelBuilder.Entity<PostTag>()
                .HasKey(x => new { x.PostId, x.TagId });

            modelBuilder.Entity<PostTag>()
                .HasOne(x => x.Post)
                .WithMany(x => x.PostTags);

            modelBuilder.Entity<PostTag>()
                .HasOne(x => x.Tag)
                .WithMany(x => x.PostTags);

            modelBuilder.Entity<PostTag>()
                .HasData(
                    new PostTag { PostId = 1, TagId = 1 },
                    new PostTag { PostId = 1, TagId = 2 }
                );

            base.OnModelCreating(modelBuilder);
        }
    }
}

UnitTest1.cs

        [Fact]
        public void Test1()
        {
            var ctx = CreateContext();
            var post = ctx.Posts.Include(x => x.PostTags).SingleOrDefault(x => x.Id == 1);
            if (post != null)
            {
                post.PostTags.RemoveAt(1);
            }

            
            ctx.ChangeTracker.DetectChanges();
            Debug.WriteLine(ctx.ChangeTracker.DebugView.LongView);

            var tag = ctx.Tags.Include(x => x.PostTags).ToList();
            Debug.WriteLine(ctx.ChangeTracker.DebugView.LongView);

            ctx.ChangeTracker.DetectChanges();
            Debug.WriteLine(ctx.ChangeTracker.DebugView.LongView);


            ctx.SaveChanges();
        }
 Post {Id: 1} Unchanged
   Id: 1 PK
   Content: 'blababa'
   Title: 'How to use vs?'
   PostTags: [{PostId: 1, TagId: 1}]
 PostTag {PostId: 1, TagId: 1} Unchanged
   PostId: 1 PK FK
   TagId: 1 PK FK
   Post: {Id: 1}
   Tag: <null>
 PostTag {PostId: 1, TagId: 2} Deleted
   PostId: 1 PK FK
   TagId: 2 PK FK
   Post: <null>
   Tag: <null>
 Post {Id: 1} Unchanged
   Id: 1 PK
   Content: 'blababa'
   Title: 'How to use vs?'
   PostTags: [{PostId: 1, TagId: 1}]
 PostTag {PostId: 1, TagId: 1} Unchanged
   PostId: 1 PK FK
   TagId: 1 PK FK
   Post: {Id: 1}
   Tag: {Id: 1}
 PostTag {PostId: 1, TagId: 2} Deleted
   PostId: 1 PK FK
   TagId: 2 PK FK
   Post: <null>
   Tag: {Id: 2}
 Tag {Id: 1} Unchanged
   Id: 1 PK
   Text: '.NET'
   PostTags: [{PostId: 1, TagId: 1}]
 Tag {Id: 2} Unchanged
   Id: 2 PK
   Text: 'C#'
   PostTags: [{PostId: 1, TagId: 2}]
Post {Id: 1} Unchanged
  Id: 1 PK
  Content: 'blababa'
  Title: 'How to use vs?'
  PostTags: [{PostId: 1, TagId: 1}]
PostTag {PostId: 1, TagId: 1} Unchanged
  PostId: 1 PK FK
  TagId: 1 PK FK
  Post: {Id: 1}
  Tag: {Id: 1}
PostTag {PostId: 1, TagId: 2} Deleted
  PostId: 1 PK FK
  TagId: 2 PK FK
  Post: <null>
  Tag: {Id: 2}
Tag {Id: 1} Unchanged
  Id: 1 PK
  Text: '.NET'
  PostTags: [{PostId: 1, TagId: 1}]
Tag {Id: 2} Unchanged
  Id: 2 PK
  Text: 'C#'
  PostTags: [{PostId: 1, TagId: 2}]

Include provider and version information

EF Core version:5.0.12
Database provider: Pomelo.EntityFrameworkCore.MySql
Target framework:NET 5.0
Operating system:
IDE: vscode latest

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions