简体   繁体   中英

One to many relationship in Entity core deleting the previous records in child table as part of parent-child update

I have 3 entities like Book, Author, and BookAuthor(junction table), I have master data for Author and one book can have multiple Authors, so BookAuthor will store the BookId and AuthorId.

Here, the issue is I have created book records with 2 authors initially, so it saved the one record into the Book table and 2 records into BookAuthor table. In the next request, I have added one more author, expectation is it should insert one more record into the BookAuthor table and it should contain 3 records. But what is happening is as part of the update it is deleting the previous two records and Inserting the new record into the BookAuthor table.

Book.cs

    private string _name;
    private int _pageCount;
    private List<BookAuthor> _bookAuthors = new List<BookAuthor>();

    public Book()
    {
            
    }

    public Book(string name, int pageCount)
    {
        _name = name;
        _pageCount = pageCount;
    }

    public int Id { get; set; }
    public string Name => _name;
    public int PageCount => _pageCount;

    public IEnumerable<BookAuthor> BookAuthors => _bookAuthors;

Author.cs

    private string _name;
    private int _age;
    private List<BookAuthor> _bookAuthors = new List<BookAuthor>();

    public Author()
    {

    }

    public Author(string name, int age)
    {
        _name = name;
        _age = age;
    }
    public int Id { get; set; }
    public string Name => _name;
    public int Age => _age;

    public IEnumerable<BookAuthor> BookAuthors => _bookAuthors;

BookAuthor.cs

    private int _bookId;
    private int _authorId;

    private Book _book;
    private Author _author;

    public BookAuthor()
    {

    }

    public BookAuthor(int bookId, int authorId)
    {
        _bookId = bookId;
        _authorId = authorId;
    }
    public int Id { get; set; }
    public int BookId => _bookId;
    public int AuthorId => _authorId;

    public Book Book => _book;
    public Author Author => _author;

Using the above created the Entity configuration.

 public class AuthorConfiguration : IEntityTypeConfiguration<Author>
   {
    public void Configure(EntityTypeBuilder<Author> builder)
    {
        builder.HasKey(b => b.Id);
        builder.Property(b => b.Name).HasField("_name");
        builder.Property(b => b.Age).HasField("_age");
        builder.HasMany(t => t.BookAuthors).WithOne(t => 
         t.Author).HasForeignKey(t => t.AuthorId);
  builder.Metadata.FindNavigation(nameof(Book.BookAuthors)).SetPropertyAccessMode(PropertyAccessMode.Field);
    }
}


  
  public class BookConfiguration : IEntityTypeConfiguration<Book>
{
    public void Configure(EntityTypeBuilder<Book> builder)
    {
        builder.HasKey(b => b.Id);
        builder.Property(b => b.Name).HasField("_name");
        builder.Property(b => b.PageCount).HasField("_pageCount");
        builder.HasMany(t => t.BookAuthors).WithOne(t => t.Book).HasForeignKey(t => t.BookId);

        builder.Metadata.FindNavigation(nameof(Book.BookAuthors)).SetPropertyAccessMode(PropertyAccessMode.Field);
    }
}


  public class BookAuthorConfiguration : IEntityTypeConfiguration<BookAuthor>
{
    public void Configure(EntityTypeBuilder<BookAuthor> builder)
    {
        builder.HasKey(b => b.Id);
        builder.Property(b => b.BookId).HasField("_bookId");
        builder.Property(b => b.AuthorId).HasField("_authorId");
        builder.HasOne(a => a.Book).WithMany(a => a.BookAuthors).HasForeignKey(a => a.BookId);
        builder.HasOne(a => a.Author).WithMany(a => a.BookAuthors).HasForeignKey(a => a.AuthorId);
    }
}

Update Code

  public async Task<Result> UpdateReference(BookDto bookDto)
    {
        var bookresult = await _bookRepository.GetById(bookDto.Id);
        bookresult.Value.Update(bookDto.Name, bookDto.PageCount, bookDto.AuthorIds);

        var result = await _bookRepository.Update(bookresult.Value);
        if (!result.IsSucceeded)
            return Result.Fail(result.GetErrorString());

        return Result.Ok();

    }

    public void Update(string name, int pageCount, List<int> authersId)
    {
        _name = name;
        _pageCount = pageCount;
        UpdateAutherId(authersId);
    }

    private void UpdateAutherId(List<int> authersId)
    {
        if (authersId.Any())
        {
            var bookAuthors = GetBookAuthors(authersId);
            var newBookAuthors = bookAuthors.Except(_bookAuthors).ToList();
            var deletedBookAuthors = _bookAuthors.Except(bookAuthors).ToList();
            if (newBookAuthors.Any())
            {
                _bookAuthors.AddRange(newBookAuthors);
            }
            if (deletedBookAuthors.Any())
            {
                foreach (var bookAuthor in deletedBookAuthors)
                {
                    _bookAuthors.Remove(bookAuthor);
                }
            }
        }
        else
        {
            _bookAuthors.RemoveRange(0, _bookAuthors.Count);
        }
    }

   public override async Task<Result<Book>> GetById(int id)
    {
        var result = await _bookAuthorContext.Books
            .Include(a => a.BookAuthors)
            .FirstOrDefaultAsync(a => a.Id == id);

        if (result == null)
            return Result.Fail<Book>("no Data found", ApplicationResponseCode.BadRequest, ApplicationResponseCode.BadRequest);

        return Result.Ok<Book>(result);
    }

It seems to me that the problem is because you don't fetch the BookAuthor entities when you retrieve specific book from DB.

You can rely on EF here and simply retrieve the Book entity from db but don't forget to Include the BookAuthor entities.

Then all you need to call is simply replace existing BookAuthor collection with another one and after saving the changes, EF will perform inserts/deletes automatically

var myBook = db.Books.Include(b => b.BookAuthors).SingleOrDefalut(b => b == ...);
myBook.BookAuthors = newBookAuthors;
db.SaveChanges();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM