简体   繁体   English

插入后获取实体导航属性

[英]Get entity navigation properties after insert

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.有了这个,我就有了所有明显必要的东西,比如 DbContext 和映射。

Now let's say I create a Reward entity and insert it like this:现在假设我创建了一个 Reward 实体并像这样插入它:

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.我显然有一个 ID 为 1 的活动,所以 FK 约束很高兴。 After this insert, my reward entity has it's new Identity Id set.在此插入后,我的奖励实体设置了新的身份 ID。 Now the problem is that reward is still just the Reward entity I created.现在的问题是奖励仍然只是我创建的奖励实体。 And with this, the reward.Campaign property is null.有了这个,reward.Campaign 属性为空。 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.似乎 EF 将插入的实体保留在内存中,然后当我执行 .SingleOrDefault(a => a.Id == reward.Id) 时,它只是返回内存中的实体,而不是新代理。 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?我是否可能以错误的方式插入?

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. SaveChanges()在加载复杂属性方面不做任何事情。 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);您的行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.在加载Campaign也没有任何作用,因为您的奖励对象未附加到上下文。 You need to explicitly tell EF to load that complex object or attach it then let lazy loading work its magic.您需要明确告诉 EF 加载该复杂对象或附加它,然后让延迟加载发挥其魔力。

So, after you context.SaveChanges();所以,在你context.SaveChanges(); you have three options for loading reward.Campaign :您可以通过三个选项加载reward.Campaign

  1. Attach() reward to the context so that Campaign can be lazily loaded (loaded when accessed) Attach()奖励到上下文,以便可以延迟加载Campaign (访问时加载)

     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.注意:您将只能在上下文范围内延迟加载reward.Campaign ,因此如果您不打算在上下文生命周期内访问任何属性,请使用选项 2 或 3。

  2. Manually Load() the Campaign property手动Load() Campaign属性

     context.Entry(reward).Reference(c => c.Campaign).Load();

    Or if Campaign was a collection, for example Campaigns :或者如果Campaign是一个集合,例如Campaigns

     context.Entry(reward).Collection(c => c.Campaigns).Load();
  3. Manually Include() the Campaign property手动Include() Campaign属性

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

    Although, I'd suggest Load since you already have reward in memory.虽然,我建议Load因为您已经在记忆中获得了reward

Check out the Loading Related Objects Section on this msdn doc for more information.查看此 msdn 文档上的加载相关对象部分以获取更多信息。

As you are creating your reward object as new Reward() , EF doesn't have a proxy.当您将reward对象创建为new Reward() ,EF 没有代理。 Instead, create it using DbSet.Create like this:相反,使用 DbSet.Create 创建它,如下所示:

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

Next attach it to your DbSet:接下来将其附加到您的 DbSet:

context.Rewards.Attach(reward);

Finally, you can now use lazy loading to get related entities:最后,您现在可以使用延迟加载来获取相关实体:

var campaign = reward.Campaign;

I have a simple Solution around the problem.我有一个简单的解决方案来解决这个问题。

instead of adding the CampaignID to the reward, add the campaign Object.. so:不是将 CampaignID 添加到奖励中,而是添加活动 Object.. 所以:

var _campaign = context.Campaign.First(c=>c.Id == 1);//how ever you get the '1'
var reward = new Reward { Campaign = _campaign };
context.Set<Reward>().Add(reward);
context.SaveChanges();

//reward.Campaign is not null

Entity framework does all the heavy lifting here.实体框架在这里完成了所有繁重的工作。

You're probably thinking that it's a waste to load the entire Campaign object but if you are going to be using it (from what it looks like, seems you are) then I don't see why not.您可能认为加载整个 Campaign 对象是一种浪费,但如果您打算使用它(从它的外观来看,您似乎是这样),那么我不明白为什么不使用它。 You can even use the include statement when fetching it above if you need to access navigation properties from the Campaign object...如果您需要从 Campaign 对象访问导航属性,您甚至可以在上面获取它时使用 include 语句...

var _campaign = context.Campaign.include(/*what ever you may require*/).First(c=>c.Id = 1);

Did you try using Include() ?您是否尝试使用Include() Something like this:像这样的东西:

reward = context.Set<Reward>().Include("Campaigns").SingleOrDefault(a => a.Id == reward.Id);

In addition to Carrie Kendall and DavidG (in VB.NET):除了Carrie KendallDavidG (在 VB.NET 中):

Dim db As New MyEntities
Dim r As Reward = = db.Set(Of Reward)().Create()
r.CampaignId = 5
db.Reward.Add(r) ' Here was my problem, I was not adding to database and child did not load
db.SaveChanges()

Then, property r.Campaign is available然后,属性r.Campaign可用

if you have more than one navigation properties or want to add more than one records it may be hard to do it in these ways.如果您有多个导航属性或想要添加多个记录,以这些方式可能很难做到。

so i suggest if the memory doesn't matter create a new context object after adding your records , and use it instead所以我建议如果内存无关紧要在添加记录后创建一个新的上下文对象,然后使用它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM