Reputation: 720
So I'm trying to update each row in my database using EF Core this is my approach:
foreach(var item in items)
{
var theItem = db.CurrentPriceTableModels.FirstOrDefault(x => x.Id == item.Value.Id);
if (theItem != null)
{
Console.WriteLine($ "{item.Value.Id}: Inserting item data /w datapoint");
var currentPriceTableModel = new CurrentPriceTableModel();
currentPriceTableModel.Id = item.Value.Id; //This is the itemId not the rowId
//more properties
...
foreach(var datapoint in datapoints) {
currentPriceTableModel.The30DayPoints.Add(datapoint);
}
db.CurrentPriceTableModels.Update(currentPriceTableModel);
}
}
However, I'm getting this error and I'm not sure why.
System.InvalidOperationException: The instance of entity type 'MyModel' 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.
What's the proper way of updating a row in a database using EF Core?
Upvotes: 0
Views: 598
Reputation: 74710
The “correct” way is to download an item, change things on it and send it back
What you’re doing is downloading the item...
var theItem = db.CurrentPriceTableModels.FirstOrDefault(x => x.Id == item.Value.Id);
...then when you found it (and we know it was found because the thing you just downloaded isn’t null - if it was this code wouldn’t be running) you’re creating another item with the same ID...
var currentPriceTableModel = new CurrentPriceTableModel();
currentPriceTableModel.Id = item.Value.Id;
...and trying to attach the new item to the graph of entities that the dB context knows about, and save it (which presumably would result in a PK violation anyway, if the dB context wasn’t catching it first)
Edit the existing item you already found rather than creating a new one with the same id
Upvotes: 2
Reputation: 1001
Entity-Framework: DB-Context and Model relationship
What Entity Framework does is that it creates a context, where your entity model lives (db), which you can work with, and those "entities" will be persisted back to the database when you save the context. That said, it should be clearer now that for every entity, only one object instance representing it can exist within the same context.
So it is not a good idea to freely create instances that represent an entity which is already represented by another instance somewhere in the context.
var currentPriceTableModel = new CurrentPriceTableModel();
currentPriceTableModel.Id = item.Value.Id;
That way, you have two instances, both have the same unique id, and you have changed one of these instances. Thats what C# is trying to tell you with this rather cryptic error message: It says, I can't do that, because in case you save now, I wouldn't know how to proceed.
One instance says A, the other says B, it is ambiguous.
How to update?
Do not create a new instance, use the existing one, and (assuming everything else is correct) it should work. Arman Ebrahimpour has that in his answer. (dont' know why it was downvoted)
Upvotes: 3
Reputation: 4461
Try this:
foreach(var item in items)
{
var theItem = db.CurrentPriceTableModels.FirstOrDefault(x => x.Id == item.Value.Id);
if (theItem != null)
{
Console.WriteLine($ "{item.Value.Id}: Inserting item data /w datapoint");
// Update properties of theItem
...
foreach(var datapoint in datapoints)
{
theItem.The30DayPoints.Add(datapoint);
}
db.CurrentPriceTableModels.Update(theItem);
}
}
Upvotes: 1