插入后获取实体导航属性
本文关键字:导航 属性 实体 获取 插入 | 更新日期: 2023-09-27 18:28:18
我有以下两个类:
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; }
}
有了这个,我就有了所有明显必要的东西,比如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
我显然有一个Id为1的活动,所以FK约束是令人高兴的。插入后,我的奖励实体将设置新的身份Id。现在的问题是,奖励仍然只是我创建的奖励实体。这就是回报。市场活动属性为null。EF似乎将插入的实体保留在内存中,然后当我执行.SingleOrDefault(a=>a.Id==reward.Id)时,它只是返回内存中的实体,而不是新的代理。这可能是一件好事。
所以问题是:如何在插入后访问或加载导航属性,或者获得一个将导航属性作为代理的新代理。
我可能插错了吗?
如果我理解正确的话,您正试图在通过外键属性建立关系后急切地加载一个复杂的属性。
CCD_ 1不以加载复杂属性的方式执行任何操作。如果你添加新对象,它最多会设置你的主键属性。
您的线路reward = context.Set<Reward>().SingleOrDefault(a => a.Id == reward.Id);
也不会以加载Campaign
的方式执行任何操作,因为您的奖励对象未附加到上下文。您需要显式地告诉EF加载该复杂对象或附加它,然后让懒惰加载发挥其魔力。
因此,在context.SaveChanges();
之后,您有三个加载reward.Campaign
:的选项
-
Attach()
奖励上下文,以便Campaign
可以延迟加载(访问时加载)context.Rewards.Attach(reward);
注意:您只能在上下文范围内延迟加载
reward.Campaign
,因此如果您不打算在上下文寿命内访问任何属性,请使用选项2或3。 -
手动
Load()
SaveChanges()
0属性context.Entry(reward).Reference(c => c.Campaign).Load();
或者如果
Campaign
是一个集合,例如Campaigns
:context.Entry(reward).Collection(c => c.Campaigns).Load();
-
手动
Include()
Campaign
属性reward = context.Rewards.Include("Campaigns") .SingleOrDefault(r => r.Id == reward.Id);
尽管如此,我还是建议使用
Load
,因为您的内存中已经有reward
了。
有关详细信息,请查看此msdn文档的"加载相关对象"部分。
当您将reward
对象创建为new Reward()
时,EF没有代理。相反,使用DbSet创建它。创建方式如下:
var reward = context.Set<Reward>().Create();
reward.CampaignId = 5;
context.SaveChanges();
接下来将其附加到您的数据库集:
context.Rewards.Attach(reward);
最后,您现在可以使用延迟加载来获取相关实体:
var campaign = reward.Campaign;
我有一个简单的解决方案。
不要将CampaignID添加到奖励中,而是添加活动对象。。所以:
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
实体框架承担了所有繁重的工作。
你可能会认为加载整个Campaign对象是一种浪费,但如果你要使用它(从它的外观来看,你似乎是),那么我不明白为什么不这样做。如果您需要从Campaign对象访问导航属性,您甚至可以在上面获取include语句。。。
var _campaign = context.Campaign.include(/*what ever you may require*/).First(c=>c.Id = 1);
除了Carrie Kendall和DavidG(在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()
然后,属性r.Campaign
可用
您尝试过使用Include()
吗?类似这样的东西:
reward = context.Set<Reward>().Include("Campaigns").SingleOrDefault(a => a.Id == reward.Id);
如果您有多个导航属性或想要添加多个记录,那么用这些方法可能很难做到。
因此,我建议如果内存无关紧要在添加记录后创建一个新的上下文对象,并使用它来代替