I'm studying Entity Framework Core
version 8 using a Blazor
project. The scenario is quite basic: I like to create a simple blog. I have an Article object that has 2 ICollection
properties: Category and Tags
[Table("Articles")]
public class Article : Table
{
[JsonPropertyName("body")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Body { get; set; }
public ICollection<Category>? Categories { get; set; }
public ICollection<Tag>? Tags { get; set; }
}
Then, the class Category is defined like the following (Tag is similar)
[Table("tbl_Categories")]
public class Category : Table
{
public string? Name { get; set; }
public ICollection<Article>? Articles { get; set; }
}
In the database, I have 3 tables: Articles, Categories and EF generates a linked table called ArticleCategory. This table is a link between the 2 main tables, but I don't have a representation in my code.
The issue starts when I want to update the Article object. If I pass the existing values for Category, I get this error
An error occurred while saving the entity changes. See the inner exception for details.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Violation of PRIMARY KEY constraint 'PK_ArticleCategory'. Cannot insert duplicate key in object 'ArticleCategory'. The duplicate key value is (8, 15).
So, I think I have to delete this table first. I wrote this code to delete the records in the link table and then call for the update.
public void DeleteCategoriesByArticle(long id)
{
var article = localDb?.Articles?
.Include(a => a.Categories)?
.Where(a => a.ID == id)
.FirstOrDefault();
if (article != null)
{
bool hasChanges = false;
if (article.Categories != null && article.Categories.Count() > 0)
{
article.Categories?.Clear();
hasChanges = true;
}
if (hasChanges)
localDb?.SaveChanges();
}
}
After that, I call the function for the update. In this case I get another error
The instance of entity type 'Article' cannot be tracked because another instance with the same key value for {'ID'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
After a quick search, I changed how I retrieved the record
var article = localDb?.Articles?
.AsNoTracking()
.Include(a => a.Categories)?
.Where(a => a.ID == id)
.FirstOrDefault();
Now, I don't get the Violation of PRIMARY KEY
error as before. I have created a generic repository and the Update
function is like that
public void Update(T entity)
{
_log.LogDebug($"[{nameof(T)}] Update an entity");
if (entity == null)
throw new ArgumentNullException(nameof(entity));
if (entity.ModifiedAt == DateTime.MinValue)
entity.ModifiedAt = DateTime.UtcNow;
_db.Entry(entity).State = EntityState.Modified;
_db.SaveChanges();
}
How can I update the Article record then?