Violation of PRIMARY KEY constraint in Entity Framework Core

0

I have a .NET5 Blazor Server application using EFCore5. I have two entities that have a many-to-many relationship with each other. Let's call them 'Books' and 'Tags'.
EFCore provides the BookTag join table.

On my page, I have a form that is populated with the book details and has a multi select box for the tags. I include the tags when I get the book: context.Books.Include(x=>x.Tags); In debug mode, I see the Book item has several tags. But when I update some details of the book and save the form, calling context.Books.Update(book); I get an error because of duplicate keys in the BookTag join table.
It seems EFCore tries to insert entries in that table, but it should do a merge or insert/update.

I've read numerous articles about the many-to-many but all of them just show how to retrieve data. I can't find an example of how to update.

Edit:
I'm using the GenericRepository as explained by @carl-franklin in his excellent BlazorTrain series.

Edit2:
Here is some relevant code, I'm now not using the GenericRepo:
Startup.cs
services.AddDbContextFactory<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DbConnection")));

ApplicationDbContext.cs has only the DbSets.

Book.cs

[Key] 
public string Code { get; set; }
public string Name { get; set; } = "";
public virtual ICollection<Tag> TagCollection { get; set; }

Tag.cs

[Key] 
public string Code { get; set; }
public string Name { get; set; } = "";
public virtual ICollection<Book> BookCollection { get; set; }

Book.razor.cs

[Inject] private IDbContextFactory<ApplicationDbContext> contextFactory { get; set; }
private ApplicationDbContext context { get; set; }
protected IEnumerable<Book> BookList;

protected override async Task OnInitializedAsync()
{
    context = contextFactory.CreateDbContext();
    context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
    
    BookList = await context.Books.Include(x => x.TagCollection).ToListAsync();
}

private async Task UpdateBook(Book book)
{
    // Called after submitting form
    context.Books.Update(book);
    await context.SaveChangesAsync();
}

Even if I don't change anything, just update I get the duplicate error: Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> Microsoft.Data.SqlClient.SqlException (0x80131904): Violation of PRIMARY KEY constraint 'PK_BookTag'. Cannot insert duplicate key in object 'dbo.BookTag'

In UpdateBook() I see the book has tags, as expected. It looks like EFCore is inserting them in the join table without checking if they already exist.

c#
entity-framework
blazor-server-side
.net-5
ef-core-5.0
asked on Stack Overflow Feb 24, 2021 by Paul Meems • edited Feb 24, 2021 by Robert Harvey

1 Answer

1

Change tracking must be turned on for this to work. Otherwise, you have to track the changes yourself; Entity Framework thinks you're adding a new record, but the key is the same as an existing record, which is why you're getting the error.

answered on Stack Overflow Feb 24, 2021 by Robert Harvey

User contributions licensed under CC BY-SA 3.0