Reputation: 1504
I'm using Entity Framework and I want to update a navigational property. For example, I have a Profile
object and it has a navigational property to Gender
. I want to change the Gender
. I can update either the GenderID
of the Profile
object, which is the foreign key, or initialize the Gender
with a new Gender
object; so:
profile.GenderID = 2;
or
Profile.Gender = new Gender{ID=2, Name = "Female"};
Let's say I have a collection like Languages to represent a 1:n relationship. Do I have a list of LanguageIDs or List of Languages? How would I update the list without a hit to the DB?
If I choose the latter, what tells Entity Framework to commit either an update or an insert? Is it the primary key?
Upvotes: 3
Views: 2319
Reputation: 14515
You have the following options:
1. Update the Foreign Key field in the parent object:
profile.GenderID = 2;
This has the effect of updating that field in the model, then after you call .SaveChanges();
on the context the database will be updated as will the navigation property on your object.
2. Update the navigation property directly to an EXISTING object already attached to the context:
for example:
var femaleEntity = context.Genders.First(g=>g.Name == "Female");
profile.Gender = femaleEntity;
in this instance the Navigation Property is updated right away but the .GenderId
field is not updated on the profile
object until you call context.SaveChanges();
whereupon EF will write the new value to the GenderId column in the database and update the .GenderId
property on the profile
object.
3. Update the navigation property with a NEW object:
Profile.Gender = new Gender{ID=2, Name = "Female"};
Here EF will attempt to ADD a new Gender row to the database with ID of 2 and Name = female. You almost certainly only want to do this if there is not already a 'Female' row in the Gender table of the database and if the Gender ID is an identity allocated by the database it will be overwritten with the allocated value upon calling .SaveChanges().
Ignoring the subtleties about when our objects are updated by EF, the first 2 options are roughly equivalent* but the 3rd option has a different behavior. It is up to us to know (or to determine) whether we need to link to an existing Gender object or to add a new one to the data store.
Exactly the same principle applies to your 1:Many relationships too:
profile.Languages = new List<Languages>
{
new Language{Name = "Spanish"}
}
creates a new row in the languages table, whereas:
var spanish = context.Languages.First(l=>l.Name == "Spanish");
profile.Languages = new List<Languages>
{
spanish
}
finds the existing row with name 'Spanish' then updates the navigational property.
If you have a list of language ids stored in a variable you want to update the navigation property with the associated language objects you could do:
var languagesToAdd = context.Languages.Where(l=>languageIds.Contains(l.ID)).ToList();
profile.Languages = languagesToAdd;
*Of course there is a performance penalty with option 2 if you don't already have an attached Gender object in memory because fetching the data, for example, by calling .First()
as in my example, would (of course) need another round trip to the database.
Upvotes: 4