2015-01-08 38 views
0

我會嘗試簡單地解釋我的實體框架模型。我有一個User對象,其中包含零個或多個UserInterest對象的集合。每個用戶興趣對象只有三個屬性,唯一ID,用戶ID和說明。無法更新實體框架虛擬列表對象

每當用戶更新User對象時,它也應該更新相關的UserInterest對象,但由於這些對象是自由形式的(即不是允許的興趣列表的一部分),我希望用戶通過一個類型爲「字符串「到他們所有興趣的名稱的網絡方法。理想情況下,代碼將查看用戶現有的興趣列表,刪除不再相關的任何內容並添加新內容,並保留已存在的內容。

我的對象模型定義

[Table("User")] 
public class DbUser { 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 

    public virtual IList<DbUserInterest> Interests { get; set; } 
} 

[Table("UserInterest")] 
public class DbUserInterest : IEntityComparable<DbUserInterest> 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public long Id { get; set; } 

    public virtual DbUser User { get; set; } 
    public int? UserId { get; set; } 
} 

上下文流利的映射

modelBuilder.Entity<DbUser>() 
    .HasKey(u => u.UserId); 
modelBuilder.Entity<DbUser>() 
    .Property(u => u.UserId) 
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
modelBuilder.Entity<DbUser>() 
    .HasMany(u => u.Interests) 
    .WithRequired(p => p.User) 
    .WillCascadeOnDelete(true); 

modelBuilder.Entity<DbUserInterest>() 
    .HasKey(p => p.Id); 
modelBuilder.Entity<DbUserInterest>() 
    .Property(p => p.Id) 
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
modelBuilder.Entity<DbUserInterest>() 
    .HasRequired(p => p.User) 
    .WithMany(u => u.Interests) 
    .WillCascadeOnDelete(true); 

而且最後我的webmethod代碼和庫法做更新

public UpdateUserProfileDetailsResponse UpdateUserProfileDetails(UpdateUserProfileDetailsRequest request) 
{ 
    try 
    { 
     var dbItem = _userDataRepository.GetItem(request.Header.UserId); 

     dbItem.Interests.Clear(); 
     foreach (var dbInterest in request.UserInterests) 
      dbItem.Interests.Add(new DbUserInterest { Name = dbInterest, UserId = dbItem.UserId}); 

     _userDataRepository.UpdateItem(dbItem); 
     _userDataRepository.Save(); 
    } 
    catch (Exception ex) 
    { 
    } 
} 

public override bool UpdateItem(DbUser item) 
{ 
    var dbItem = GetItem(item.UserId); 
    if (dbItem == null) 
     throw new DataRepositoryException("User not found to update", "UserDataRepository.UpdateItem"); 

    var dbInterests = Work.Context.UserInterests.Where(b => b.UserId == item.UserId).ToList(); 
    var interestsToRemove = (from interest in dbInterests let found = item.Interests.Any(p => p.IsSame(interest)) where !found select interest).ToList(); 
    var interestsToAdd = (from interest in item.Interests let found = dbInterests.Any(p => p.IsSame(interest)) where !found select interest).ToList(); 

    foreach (var interest in interestsToRemove) 
     Work.Context.UserInterests.Remove(interest); 

    foreach (var interest in interestsToAdd) 
    { 
     interest.UserId = item.UserId; 
     Work.Context.UserInterests.Add(interest); 
    }     

    Work.Context.Entry(dbItem).State = EntityState.Modified; 
    return Work.Context.Entry(dbItem).GetValidationResult().IsValid; 
} 

當我運行此,在Repository.Save()線我得到例外

Assert.IsTrue failed. An unexpected error occurred: An error occurred while updating the entries. See the inner exception for details. 

但有趣的是在將WebMethod,如果我註釋掉線dbItem.Interests.Clear();它不會拋出一個錯誤,儘管那當然你得到它認爲一切都是新的興趣增加重複或多餘的物品。但刪除這條線是我可以得到的代碼不會錯誤的唯一途徑

之前,我有興趣對象的UserId屬性設置爲不可空,然後錯誤是稍有不同,關於你的一些事情不能改變關係不可空的外鍵實體,這就是爲什麼我將該屬性更改爲可爲空,但仍然不可用。

有什麼想法?

+0

什麼是內部異常? – IronMan84

+0

這是空的煩人 – NZJames

回答

0

你不能只清除集合,然後嘗試重建它。 EF不會那樣工作。 DbContext會跟蹤其更改跟蹤器中從數據庫中返回的所有對象。這樣做會導致重複,因爲EF認爲它們根本不在變更追蹤器中,所以它們必須是全新的對象,因此必須添加到數據庫中。

您需要在UpdateUserProfileDetails方法中執行添加/刪除邏輯,否則您必須找到一種方法將request.UserInterests傳遞到您的UpdateItem方法中。因爲您需要調整現有實體,而不是請求中發現的實體(EF認爲這是新實體)。

+0

謝謝,這很好地解釋它 – NZJames

0

,你可以用這種方式嘗試 刪除

dbItem.Interests.Clear(); 

然後

foreach (var dbInterest in request.UserInterests){ 
     if(dbItem.Interests.Any()){ 
     if (dbItem.Interests.Count(i=> i.Name==dbInterest && i.UserId==dbItem.UserId) == 0){ 
      dbItem.Interests.Add(new DbUserInterest { Name = dbInterest, UserId = dbItem.UserId}); 
     } 
     } 
    }