2014-10-28 98 views
28

後,我有以下2類:獲取實體導航屬性插入

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約束高興。插入之後,我的獎勵實體擁有新的身份標識集。現在問題是獎勵仍然只是我創建的獎勵實體。與此同時,獎勵。運動屬性爲空。看起來EF似乎將插入的實體保存在內存中,然後當我執行.SingleOrDefault(a => a.Id == reward.Id)時,它只是返回內存中的實體,而不是新的代理。這可能是一件好事。

所以現在的問題是:如何做一個接入或插入後,裝載的導航屬性或獲得具有導航性能代理,以及一個新的代理。

我是在錯誤的道路也許將?

+0

貴測繪什麼樣子? – Maritim 2014-10-28 14:07:12

+0

[Entity Framework的可能的重複:我設置了外鍵,SaveChanges然後訪問導航屬性,但它不加載相關的實體。爲什麼不?](http://stackoverflow.com/questions/15552891/entity-framework-i-set-the-foreign-key-savechanges-then-access-the-navigation) – Colin 2014-10-28 16:49:53

回答

48

如果我正確理解你,你試圖通過外鍵屬性建立關係後急切地加載一個複雜的屬性。

SaveChanges()不加載複雜性的方式做任何事情。如果要添加新對象,最多隻能設置主鍵屬性。

您的線路reward = context.Set<Reward>().SingleOrDefault(a => a.Id == reward.Id); 也沒有在加載Campaign的方式,因爲您的獎勵對象沒有附加到上下文。你需要明確地告訴EF加載那個複雜的對象或附加它然後讓懶加載工作的魔力。

所以,你context.SaveChanges();後,你有裝載reward.Campaign三個選項:

  1. Attach()獎勵,這樣Campaign可以延遲加載上下文(加載訪問時)

    context.Rewards.Attach(reward); 
    

    注意:您只能在上下文範圍內延遲加載reward.Campaign,因此如果您不打算訪問上下文壽命內的任何屬性,請使用選項2或3。

  2. 手動Load()Campaign財產

    context.Entry(reward).Reference(c => c.Campaign).Load(); 
    
  3. 手動Include()Campaign財產

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

    雖然,我建議Load既然你已經有了reward在內存。

有關更多信息,請查看this msdn doc上的加載相關對象部分。

+4

第二種方法是最適合我的以及。 – 2016-07-09 00:30:48

+2

第一個選項對我不起作用 – 2017-05-09 10:05:23

9

當你正在創建reward對象new Reward(),EF沒有代理。相反,使用DbSet.Create這樣創建:

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

接下來,它連接到您的DbSet:

context.Rewards.Attach(reward); 

最後,您現在可以使用延遲加載來獲得相關實體:

var campaign = reward.Campaign; 
1

您是否嘗試過使用Include()?這樣的事情:

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

我有一個簡單的解決方案圍繞這個問題。的

,而不是添加的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對象是一種浪費,但是如果你打算使用它(看起來像是這樣),那我就不明白爲什麼了。 你甚至可以使用包含語句讀取,如果你需要從運動對象訪問導航屬性上面時,它...

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