2012-09-16 177 views
5

我使用EF代碼優先具有下列配置更新一個多對多集合與EF代碼第一

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    base.OnModelCreating(modelBuilder); 
    modelBuilder.Entity<UserProfile>() 
     .HasMany(x => x.TeamLeaders) 
     .WithMany() 
     .Map(m => m.MapLeftKey("UserId") 
     .MapRightKey("TeamLeaderId") 
     .ToTable("UserTeamLeaders")); 
} 

TeamLeaders是用戶即一個的ICollection它是一個自參考多對多關係。

用簡單的英語,用戶可以有多個團隊領導。這個配置看起來是正確的,因爲它創建了我所期望的決鬥FK/PK鏈接表。

我有一個MVC4應用程序,允許編輯,添加和刪除集合中的團隊領導。

在我的控制,我本來如下:

var original = context.UserProfiles 
     .Include("TeamLeaders") 
     .Single(x => x.UserId == model.UserId); 

    context.Entry(original).CurrentValues.SetValues(model); 

但是,最後一行是失敗,以紀念TeamLeaders集合作爲更新,當我打電話調用SaveChanges(),記錄沒有變化。

var original = context.UserProfiles 
     .Include("TeamLeaders") 
     .Single(x => x.UserId == model.UserId); 

    //context.Entry(original).CurrentValues.SetValues(model); 

    original.CopyProperties(model); 

然而,這種過猶不及,並調用SaveChanges:

相反,我在我的User類,它使用反射跨手動複製性,所以在我的控制器我現在已經寫了一個簡單CopyProperties方法嘗試將新用戶添加到與所選小組負責人的個人資料匹配的系統。

任何人都可以建議,我做錯了哪部分?我不確定是否需要更新映射,或者更改將屬性從視圖模型複製到模型的方式

回答

3

您必須根據您的更改修改original用戶的加載的TeamLeaders集合,以便更改檢測可以識別哪些領導已被刪除,哪些已被添加。當您調用SaveChanges時,EF將根據檢測到的更改爲連接表寫入相應的DELETE和INSERT語句。最簡單的方法是這樣的:

var original = context.UserProfiles 
    .Include("TeamLeaders") 
    .Single(x => x.UserId == model.UserId); 

original.TeamLeaders.Clear(); 
foreach (var teamLeader in model.TeamLeaders) 
{ 
    var user = context.UserProfiles.Find(teamLeader.UserId); 
    if (user != null) 
     original.TeamLeaders.Add(user) 
} 
context.SaveChanges(); 

Find會從上下文,如果他們已經裝取團隊領導。如果它們沒有加載,它將查詢數據庫。

如果你想避免額外的查詢,就可以把團隊領導手動上下文:

var original = context.UserProfiles 
    .Include("TeamLeaders") 
    .Single(x => x.UserId == model.UserId); 

original.TeamLeaders.Clear(); 
foreach (var teamLeader in model.TeamLeaders) 
{ 
    var user = context.UserProfiles.Local 
     .SingleOrDefault(o => o.UserId == teamLeader.UserId); 
    if (user == null) 
    { 
     user = new User { UserId = teamLeader.UserId }; 
     context.UserProfiles.Attach(user); 
    } 
    original.TeamLeaders.Add(user) 
} 
context.SaveChanges(); 

除了第一個查詢加載original這裏不涉及進一步的數據庫查詢。

BTW:你應該能夠使用強類型Include版本的EF代碼優先:

Include(u => u.TeamLeaders) 

你只需要using System.Data.Entity;在你的代碼文件,以獲得進入到這個版本。

+0

謝謝你 - 這是一種享受。我寧願不必清除/重新添加到控制器中 - 相反,如果有一種設置方法,以便它可以在模型/映射中使用一些簡單的配置/屬性來完成它自己,但這個工作,所以我現在堅持這一點。 – GGG

+0

@GGG:不幸的是,更新分離的對象圖總是相當多的代碼來編寫。沒有可以簡化工作的配置選項。 'CurrentValues.SetValues(model)'只會影響標量屬性,它不會更新任何導航屬性,正如您在第一次嘗試中所看到的。 – Slauma