Get entity navigation properties after insert

c# entity-framework entity-framework-6

Question

I have the following 2 classes:

public class Reward 
{
    public int Id { get; set; }
    public int CampaignId { get; set;
    public virtual Campaign Campaign { get; set; }
}

public class Campaign 
{
    public int Id { get; set; }
    public virtual ICollection<Reward> Rewards { get; set; }
}

With this I have all the obvious necessary stuff like a DbContext and mappings.

Now let's say I create a Reward entity and insert it like this:

var reward = new Reward { CampaignId = 1 };
context.Set<Reward>().Add(reward);
context.SaveChanges();

reward = context.Set<Reward>().SingleOrDefault(a => a.Id == reward.Id);
//reward.Campaign is null

I obviously have a campaign with Id 1 so the FK constraint is happy. After this insert, my reward entity has it's new Identity Id set. Now the problem is that reward is still just the Reward entity I created. And with this, the reward.Campaign property is null. It seems like EF is keeping the inserted entities in memory, and when I then do a .SingleOrDefault(a => a.Id == reward.Id) it simply returns the entity in memory, and not a new proxy. This is probably a good thing.

So the question is: How does one access or load the navigation properties after an insert or get a new proxy that has the navigation properties as proxies as well.

Am I perhaps inserting in the wrong way?

1
43
10/28/2014 2:07:32 PM

Accepted Answer

If I understand you correctly, you're trying to eagerly load a complex property after establishing a relationship via a foreign key property.

SaveChanges() does not do anything in the way of loading complex properties. At most, it is going to set your primary key property if you're adding new objects.

Your line reward = context.Set<Reward>().SingleOrDefault(a => a.Id == reward.Id); also does nothing in the way of loading Campaign because your reward object is not attached to the context. You need to explicitly tell EF to load that complex object or attach it then let lazy loading work its magic.

So, after you context.SaveChanges(); you have three options for loading reward.Campaign:

  1. Attach() reward to the context so that Campaign can be lazily loaded (loaded when accessed)

    context.Rewards.Attach(reward);
    

    Note: You will only be able to lazy load reward.Campaign within the context's scope so if you're not going to access any properties within the context lifespan, use option 2 or 3.

  2. Manually Load() the Campaign property

    context.Entry(reward).Reference(c => c.Campaign).Load();
    
  3. Manually Include() the Campaign property

    reward = context.Rewards.Include("Campaigns")
        .SingleOrDefault(r => r.Id == reward.Id);
    

    Although, I'd suggest Load since you already have reward in memory.

Check out the Loading Related Objects Section on this msdn doc for more information.

70
10/28/2014 6:02:22 PM

Popular Answer

As you are creating your reward object as new Reward(), EF doesn't have a proxy. Instead, create it using DbSet.Create like this:

var reward = context.Set<Reward>().Create();
reward.CampaignId = 5;
context.SaveChanges();

Next attach it to your DbSet:

context.Rewards.Attach(reward);

Finally, you can now use lazy loading to get related entities:

var campaign = reward.Campaign;


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow