Reputation: 5321
I have a table like this:
[Id] [INT] IDENTITY(1,1) NOT NULL,
..
..
[ParentId] [INT] NULL,
[CreatedOn] [DATETIME] NOT NULL,
[UpdatedOn] [DATETIME] NOT NULL
In some case I want to update the ParentId with the Id of the table like this:
_dbContext.Add(data);
if (true)
{
data.ParentId = data.Id;
}
_dbContext.Update(data);
await _dbContext.SaveChangesAsync();
When doing so, I am getting this error:
The property 'Id' on entity type 'Data' has a temporary value while attempting to change the entity's state to 'Modified'. Either set a permanent value explicitly or ensure that the database is configured to generate values for this property.
Is it possible what I am trying to do or I need to first call the SaveChangesAsync() before update?
Upvotes: 0
Views: 4325
Reputation: 13783
Entity Framework has something called a change tracker. This performs a few duties, I'll mention the ones relevant for this answer:
SaveChanges()
When you call SaveChanges()
, EF might need to INSERT
some entities, and it needs to UPDATE
some others (I'm ignoring other operations as they are irrelevant here. To keep track of this, EF's change tracker attached a particular enum called EntityState
to your entity. Based on the method you call, the enum value gets set.
_dbContext.Add(data);
var the_enum_value = _dbContext.Entry(data).State;
You will see that the_enum_value
equals EntityState.Added
. This means that when you call SaveChanges()
, an INSERT statement will be generated.
_dbContext.Update(data); //let's assume this is an existing entity you fetched
var the_enum_value = _dbContext.Entry(data).State;
Here, you will see that the_enum_value
equals EntityState.Modified
. This means that when you call SaveChanges()
, an UPDATE statement will be generated.
You added a new entity, so you clearly want to INSERT it to the database. But by calling Update
on this entity, you would change the enum value to EntityState.Modified
, therefore causing an UPDATE statement to be generated, even though there is no existing row in the database yet that you need to update.
In the past, EF just changed the enum, tried anyway, and then you'd be scratching your head as to why your changes weren't making it to the database.
Nowadays, EF is smart enough to realize that if the entity doesn't have an actual ID value yet, that setting the enum to EntityState.Modified
is going to be a bad idea, so it alerts you that you're trying to do something that won't work.
The general solution here is that you simply didn't need to call Update
. You could do this:
var data = new Data() { Name = "Foo" };
_dbContext.Add(data);
data.Name = "Bar";
await _dbContext.SaveChangesAsync();
You will see that the name hitting the database is "Bar", not "Foo". Because EF only generates the INSERT statement when you call SaveChanges
, not when you call Add
; therefore any changes made before calling SaveChanges
are still "seen" by the INSERT statement being generated.
HOWEVER, you're in a particularly special case because you're trying to access and use the ID property of the to-be-created entity. That value does not yet exist.
EF does its best to ignore this and make it work for you behind the scenes. When you call SaveChanges()
, EF will find out what the generated ID is and will silently fill it in for you so you can keep using your data
variable without needing to worry.
But I very much doubt that EF is going to be able to realize that data.ParentId
needs the same treatment.
Do I need to first call the SaveChangesAsync() before update?
In this very specific case, most likely yes. However, this is because you're trying to use the data.Id
value, and this is unrelated to the error message you reported.
Upvotes: 1