Riley Varga
Riley Varga

Reputation: 720

How do I properly update a row using EF Core?

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

Answers (3)

Caius Jard
Caius Jard

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

Michael Schönbauer
Michael Schönbauer

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

Arman Ebrahimpour
Arman Ebrahimpour

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

Related Questions