'Why won't EF Core update this item on my database?
I'm having trouble updating an item on my database. I've tried several different ways, but nothing seems to work. Here is my latest attempt:
public async Task<Finding> InsertOrUpdateItemAsync(Item localItem)
{
using (var context = new AppDbContext())
{
context.Items.Update(localItem);
context.SaveChanges();
}
}
When SaveChanges executes, I get the following error message: "The instance of entity type ItemStatus cannot be tracked because another instance with the key value ['ItemStatusId: 4'] is already being tracked.
Here are the relevant properties of my Item model:
public class Item
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ItemId { get; set; }
public ItemStatus InitialStatus { get; set; }
public ItemStatus FinalStatus {get; set; }
}
And here are the relevant properties from the ItemStatus class:
public class ItemStatus
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ItemStatusId { get; set; }
public string ItemStatusName{ get; set; }
]
Can anyone tell me what I'm doing wrong? I have checked to make sure I don't have an undisposed context somewhere. Also, when I look at the change tracker, I can see that it is tracking an entry from each row on the ItemStatus table. This doesn't seem right. Shouldn't it only track the ItemStatus that has been assigned to localItem rather than all the related entities?
I am calling the method from here:
savedItem = awaitdataService.InsertOrUpdateFindingAsync(ItemToDisplay);
The various properties of ItemToDisplay are bound to dropdown lists in the UI. I have verified that these properties are being assigned correctly before being sent to the InsertOrUpdateFindingAsync method.
I have also tried a this for the InsertOrUpdate method:
public async Task<Finding> InsertOrUpdateItemAsync(Item localItem)
{
using (var context = new AppDbContext())
{
Item itemFromDb = context.Items.Where(i => i.ItemId == localItem.ItemId).FirstOrDefault();
itemsFromDb = localItem;
context.Items.Update(localItem);
context.SaveChanges();
}
}
Solution 1:[1]
You apparently save a localItem
that refers to two ItemStatus
objects both having ItemStatusId
= 4. The cause of the error is that these ItemStatus
objects are two instances instead of one. The Update
command tries to attach both of these instances to the context.
There are two ways to fix this:
Make sure that if both statuses in
Item
are identical they both refer to the sameItemStatus
object. Depending on wherelocalItem
comes from, this may require JSON serializer settings or a modification in the code that constructs thelocalItem
object.(Preferred) Add the primitive foreign properties
InitialStatusId
andFinalStatusId
toItem
and only set these properties, not the references. Then the update is a simple update of scalar properties.
Solution 2:[2]
because,
savedItem = awaitdataService.InsertOrUpdateFindingAsync(ItemToDisplay);
this variable is itemtodisplay, you have to read from once and you keep this data in this variable, so your context to db, tracked this record when you read.
public async Task<Finding> InsertOrUpdateItemAsync(Item localItem)
{
using (var context = new AppDbContext())
{
context.Items.Update(localItem);
context.SaveChanges();
}
}
then here when you sent this variable to there, there is already tracked variable, you tried to track it one more time.
There is 2 solition;
Read this record with asnotracking so it will not track
when your update method you need to read one more time, like searhing with id and keep it in another variable, and assign the parameters which you want to update to sent variable to new read one. then save it so it will not tracked, because there is a new read, actually you read this with tracking parameter because you dont need to add asnotracking here, but it will create a problem because you are trying to change something on same tracked context. I will add basic code based on my 2.desc.
public async Task<Finding> InsertOrUpdateItemAsync(Item localItem) { using (var context = new AppDbContext()) { var data = context.Items.Where(x => x.Id == localItem.Id).FirstOrDefault(); data.Name = localItem.Name; context.Items.Update(data); context.SaveChanges(); } }
I hope, I descripted well.
but note; using update method not best, because in that example I only want to update name property but it will create queary that update all fields. You should do it with out update, alse there is 2 option here, if write update, it says hey ef mark all need to update, so it creates a query that to update all field. But this data is already tracked, if you change name like example ef core knows it so you should only write there, savechanges(); or second method is if you want to update only one record, but your record is read with asnotracking, you should access the context, get entries and change the field as modified
public void ContextAttach(TEntity entity)
{
_dataContext.Attach(entity);
_dataContext.Entry(entity).Property(Name).IsModified = true;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Gert Arnold |
Solution 2 |