Illep
Illep

Reputation: 16841

EFCore adding temporary ID by AddAsync()

I am using EFCore 5.0.0.

When I AddAsync (person); I should be getting a temporary ID, and I use this ID to add the PersonId for School (shown in code below). FInally, I will SaveChangesAsync() where everything will be saved. However, the PersonId is set to 0. I want to get the temporary ID stored instead. How can I do this.

await _dbContext.AddAsync(person);

School school = mySchool;
school.PersonId = person.Id;
await _dbContext.AddAsync(school);

await _dbContext.SaveChangesAsync();

Note: There are many SO post that talks about the temporary ID, but none is related to this post.

Upvotes: 4

Views: 3377

Answers (2)

Ivan Stoev
Ivan Stoev

Reputation: 205539

Currently accepted answer is valid, but technically incorrect. Assigning navigation property is valid approach, but not mandatory. It's even perfectly valid to not have navigation property at all. As well as explicit FK property. But there is always at least shadow FK property which can be used to setup/maintain the relationship.

So the temporary key concept is part of the EF Core from the very beginning. However EF Core 3.0 introduced a breaking change - Temporary key values are no longer set onto entity instances. The link contains an explanation of the old and new behaviors, the reason and possible solutions:

Applications that assign primary key values onto foreign keys to form associations between entities may depend on the old behavior if the primary keys are store-generated and belong to entities in the Added state. This can be avoided by:

  • Not using store-generated keys.
  • Setting navigation properties to form relationships instead of setting foreign key values.
  • Obtain the actual temporary key values from the entity's tracking information. For example, context.Entry(blog).Property(e => e.Id).CurrentValue will return the temporary value even though blog.Id itself hasn't been set.

Bullet #1 makes no sense, Bullet #2 is what is suggested in the other answer. Bullet #3 is the direct answer/solution to your question.

And applying it to your example requires just changing

school.PersonId = person.Id;

to

school.PersonId = _dbContext.Entry(person).Property(e => e.Id).CurrentValue;

Of course when you have navigation property and the related entity instance, it's better to use it and let EF Core do its magic. The temporary key is really useful when you don't have navigation property, or you don't have related entity instance and know the key, but don't want to do roundtrip to load it from database (and using fake stub entity instance can lead to unexpected side effects/behaviors). It works well with both explicit and shadow FK properties.

Upvotes: 13

Shoejep
Shoejep

Reputation: 4839

I've never seen linking entities in EF Core using the temporary id.

Typically what you would do is assign the entity and let EF sort out the ids and relationships.

i.e. in this instance, the School will be linked to the Person.

await _dbContext.AddAsync(person);

School school = mySchool;
school.Person = person;
await _dbContext.AddAsync(school);

await _dbContext.SaveChangesAsync();

Upvotes: 3

Related Questions