Reputation: 1508
I have the following model:
public class Book
{
public Guid Id { get; set; }
public List<IndexPage> IndexPages { get; set; }
}
public class IndexPage
{
public Guid Id { get; set; }
public List<IndexWord> Words { get; set; }
public int IndexType { get; set; }
public Guid BookId { get; set; }
}
public class IndexWord {
public Guid Id { get; set; }
public String Value { get; set; }
public IndexPageId { get; set; }
}
It is configured with the following configuration:
public class BookConfiguration : IEntityTypeConfiguration<Book>
{
public void Configure(EntityTypeBuilder<Book> builder)
{
builder.ToTable("Books");
builder.HasKey(b => b.Id);
builder.HasMany(b => b.IndexPages)
.WithOne()
.HasForeignKey(b => b.BookId);
}
}
public class IndexPageConfiguration : IEntityTypeConfiguration<IndexPage>
{
public void Configure(EntityTypeBuilder<IndexPage> builder)
{
builder.ToTable("IndexPages");
builder.HasKey(ip => new { ip.BookId, ip.IndexType });
builder.HasMany(ip => ip.IndexWords)
.WithOne()
.HasForeignKey(iw => iw.IndexPageId)
.HasPrincipalKey(ip => ip.Id);
builder.HasIndex(ip => ip.Id).IsUnique();
}
}
public class IndexWordConfiguration : IEntityTypeConfiguration<IndexWord>
{
public void Configure(EntityTypeBuilder<IndexWord> builder)
{
builder.ToTable("IndexWords");
builder.HasKey(iw => iw.Id);
builder.Property(iw => iw.Value).IsRequired();
}
}
Some context; The queries are performed with AsNoTracking()
and the update is called as following:
DbContext.Set<Book>.Update(book);
If the book is updated, the indexpages are in total replaced with a new set of indexpages. If calling update the first time it all seems to work correctly and inserts the rows. However when called the second time it raises an Primary Key constraint exception; Which makes sense, however I expected the old indexpages to be removed and the new indexpages to be inserted. Due to the fact that the primary key exists and update is called, not Add.
The reason behind the composite key is that a book can only have a fixed subset of indexpages. this is also the reason why the HasPrincipalKey
has been used.
When only using the IndexPage Id as a key in the configuration. The relation between the book exists, but it just keeps inserting new indexpages on top of the old indexpages (I guess due to the AsNoTracking?). Furthermore, in the code behind I add the indexpages on the book, but these initially have empty id's.
Upvotes: 1
Views: 160
Reputation: 564
If I understand correctly, the old IndexPage
entities are not being replaced by the new ones when you attempt to Update ?
You mentioned that you're using No Tracking for your queries. Without tracking the original entity, returned from your query, EF Core has no way to tell that the entity has been modified. If you want the new IndexPage
objects to replace the old ones, then you need to track the queries and configure the delete behavior for your relationships.
You can look at the EF Core docs for a reference regarding required relationships and delete behaviors. Be careful to configure these things on the proper entities, so you don't end up deleting everything by removing an IndexPage
.
Allow for change tracking and configure if the relationships are required and their delete behavior. That should accomplish what you're seeking to achieve.
Upvotes: 1