插入后获取实体导航属性

Jus*_*ger 41 c# entity-framework entity-framework-6

我有以下两个班级:

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; }
}
Run Code Online (Sandbox Code Playgroud)

有了这个,我就拥有了所有显而易见的必要内容,比如DbContext和映射.

现在让我们说我创建一个奖励实体并像这样插入:

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
Run Code Online (Sandbox Code Playgroud)

我显然有一个Id 1的广告系列,所以FK约束很开心.在此插入之后,我的奖励实体具有新的Identity Id集.现在问题是奖励仍然只是我创建的奖励实体.有了这个,reward.Campaign属性为null.似乎EF将插入的实体保留在内存中,然后当我执行.SingleOrDefault(a => a.Id == reward.Id)时,它只返回内存中的实体,而不是新的代理.这可能是一件好事.

所以问题是:如何在插入后访问或加载导航属性,或获取具有导航属性作为代理的新代理.

我可能以错误的方式插入?

Car*_*all 66

如果我理解正确,那么在通过外键属性建立关系后,你会急切地加载一个复杂的属性.

SaveChanges()在加载复杂属性方面没有做任何事情.最多,如果要添加新对象,它将设置主键属性.

您的行reward = context.Set<Reward>().SingleOrDefault(a => a.Id == reward.Id); 也不会在加载方式中执行任何操作,Campaign因为您的奖励对象未附加到上下文中.您需要明确告诉EF加载该复杂对象或附加它然后让延迟加载发挥其神奇作用.

所以,在你context.SaveChanges();有三个加载选项后reward.Campaign:

  1. Attach()奖励上下文,以便Campaign可以延迟加载(访问时加载)

    context.Rewards.Attach(reward);
    
    Run Code Online (Sandbox Code Playgroud)

    注意:您只能reward.Campaign在上下文范围内进行延迟加载,因此如果您不打算在上下文生命周期内访问任何属性,请使用选项2或3.

  2. 手动Load()Campaign财产

    context.Entry(reward).Reference(c => c.Campaign).Load();
    
    Run Code Online (Sandbox Code Playgroud)
  3. 手动Include()Campaign财产

    reward = context.Rewards.Include("Campaigns")
        .SingleOrDefault(r => r.Id == reward.Id);
    
    Run Code Online (Sandbox Code Playgroud)

    虽然,我建议Load你已经有了reward记忆.

有关更多信息,请查看此msdn doc上的"加载相关对象"部分.

  • 第二种选择对我来说也是最好的选择. (5认同)
  • 第一个选项对我不起作用 (4认同)

Dav*_*idG 9

在创建reward对象时new Reward(),EF没有代理.相反,使用DbSet.Create创建它,如下所示:

var reward = context.Set<Reward>().Create();
reward.CampaignId = 5;
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

接下来将它附加到您的DbSet:

context.Rewards.Attach(reward);
Run Code Online (Sandbox Code Playgroud)

最后,您现在可以使用延迟加载来获取相关实体:

var campaign = reward.Campaign;
Run Code Online (Sandbox Code Playgroud)