I am using this Entity class with Entity Framework 5 Code First:
public class Survey { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } public string SurveyName { get; set; } [Required] public int ClientID { get; set; } [ForeignKey("ClientID")] public virtual Client Client { get; set; } }
And in my Controller's Create method I do this:
Survey entity = new Survey() { SurveyName = "Test Name", ClientID = 4 }; db.Surveys.Add(entity); db.SaveChanges(); Client c1 = entity.Client; //Why is this null? Client c2 = db.Clients.Find(entity.ClientID); //But this isn't? string s2 = c2.ClientName; string s1 = c1.ClientName; //null reference thrown here
The Client navigation property remains null after SaveChanges. I expected the call to load the Client from the database because the foreign key exists. Why didn't it do that?
EDIT The code here comes from when my controllers were dependent on DbContext
. Not long after I got this working I re-factored the code to use repositories and a unit of work. Part of that move was driven by the fact that it just felt wrong to use Create
when I wanted to use new
. What happened then was that I hit a problem with how to ensure proxies are created when using the repository pattern.
A navigation property is an optional property on an entity type that allows for navigation from one end of an association to the other end. Unlike other properties, navigation properties do not carry data. A navigation property definition includes the following: A name.
The SaveChanges method of the DbContext prepares the Insert , Update & Delete Queries. It does so by tracking the changes to each of the entities' Context is tracking. Whenever we query the database for entities, the Context retrieves them and mark the entity as Unchanged .
The [ForeignKey(name)] attribute can be applied in three ways: [ForeignKey(NavigationPropertyName)] on the foreign key scalar property in the dependent entity. [ForeignKey(ForeignKeyPropertyName)] on the related reference navigation property in the dependent entity.
Returns. The number of state entries written to the underlying database. This can include state entries for entities and/or relationships.
The database has only foreign key values, so when EF Core creates an entity instance from the database it uses the foreign key values to set reference navigations and add entities to collection navigations as appropriate. For example, consider a query for blogs and its associated posts and assets:
See Relationships for more information on how to model and configure relationships. EF Core keeps navigations in alignment with foreign key values and vice versa. That is, if a foreign key value changes such that it now refers to a different principal/parent entity, then the navigations are updated to reflect this change.
Knowledge Base Online Examples entity framework does not load navigation property after adding object c#entity-frameworkentity-framework-6 Question I have MVC project and EF6 model.
Relationships in EF. Every object can have a navigation property for every relationship in which it participates. Navigation properties allow you to navigate and manage relationships in both directions, returning either a reference object (if the multiplicity is either one or zero-or-one) or a collection (if the multiplicity is many).
To ensure that lazy loading of a navigation property will work after you've created the parent you must not create the Survey
with the new
operator but create it by means of the context instance because it will instantiate a dynamic proxy that is capable to lazily load the related Client
. That's what the DbSet<T>.Create()
method is for:
Survey entity = db.Surveys.Create(); entity.SurveyName = "Test Name"; entity.ClientID = 4; db.Surveys.Add(entity); db.SaveChanges(); Client c1 = entity.Client; string s1 = c1.ClientName; // will work now if a Client with ID 4 exists in the DB
Just to emphasize: It's not the line entity.ClientID = 4;
or db.Surveys.Add(entity);
or db.SaveChanges
that loads the client from the DB, but the line Client c1 = entity.Client;
(lazy loading).
Like @NicholasButler said, calling SaveChanges
does what it says on the tin - you can see this if you debug your code: the Intellitrace output will show the SQL it has generated for the insert/update you are persisting, but there will be no subsequent select.
Keep in mind that unless you are eager loading (using the Include
method), related entities are not loaded when performing a retrieval, so it stands to reason that creating/updating them wouldn't either.
The Entity Framework (from I think versions 4.1 and up) supports lazy loading. What this means is that if it's enabled, code like Client c1 = entity.Client;
should load up that Client
object. To be clear, this operation is not directly related to the SaveChanges
call.
It would pay to check whether db.Configuration.LazyLoadingEnabled
is set to true
. If not, try setting it to be true
and see if Client c1 = entity.Client;
is still null.
In short, calling SaveChanges
does not trigger a load, but if lazy loading is enabled, accessing entity.Client
should trigger a load of the entity if it hasn't already been loaded.
Edit:
I should've though of this earlier, but you aren't going to be getting lazy loading on your Survey entity
object. The reason is that EF works its lazy loading magic by creating a class derived from your one but overriding the properties marked as virtual
to support lazy loading. It does this when you perform a retrieval, so your entity
object will not lazy load anything as it stands.
Try this just after your call to SaveChanges
:
Survey entity2 = db.Surveys.Find(entity.ID); Client c1 = entity2.Client;
This should exhibit the behaviour you are after.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With