2016-02-29 67 views
2

我有一個奇怪的問題。我正在使用通用存儲庫模式和Linq到SQL。我有許多對象是dbml生成的對象之間的關係,這裏是問題。我在嘗試更新播放器對象時遇到錯誤。當我嘗試更新玩家的技能名稱時發生錯誤。這是我收到的例外:Linq到SQL通用存儲庫模式更新問題

「System.InvalidOperationException」類型的異常出現在System.Data.Linq.dll但在用戶代碼

其他信息沒有處理:試圖消除技能和玩家技能之間的關係。但是,其中一個關係的外鍵(PlayerSkill.Skill_ID)不能設置爲空。

這裏是更新方法。

public void Update(PlayerEntity player) 
    { 
     Player p = Mapper.Map<PlayerEntity, Player>(player); 
     _unitOfWork.SkillRepository.AddOrUpdate(p.PlayerSkills.Select(i => i.Skill).ToList()); 
     _unitOfWork.ProfileRepository.AddOrUpdate(p.Profile); 
     _unitOfWork.SocialAccountRepository.AddOrUpdate(p.SocialAccount); 
     _unitOfWork.PlayerRepository.AddOrUpdate(p); 
    } 

AddOrUpdate方法上回購:

public void AddOrUpdate(ICollection<TEntity> entities) 
    { 
     foreach (var e in entities) 
     { 
      AddOrUpdate(e); 
     } 
    } 

public void AddOrUpdate(TEntity entity) 
    { 
     if (GetPrimaryKeyValue(entity) > 0) 
     { 
      Update(entity); 
     } 
     else 
     { 
      Insert(entity); 
     } 
    } 

更新 DataLINQ層

public void Update(TEntity entity) 
    { 
     if (entity == null) 
     { 
      throw new ArgumentNullException("entity"); 
     } 

     var original = GetById(GetPrimaryKeyValue(entity)); 

     ApplyChanges(original, entity); 

     _context.SubmitChanges(); 
    } 

最後上方法; ApplyChanges

private void ApplyChanges<F, S>(F originalEntity, S newEntity) 
    { 
     var entityType = typeof(F); 
     var entityProperties = entityType.GetProperties(); 
     foreach (var propertyInfo in entityProperties) 
     { 
      var currentProperty = entityType.GetProperty(propertyInfo.Name); 
      currentProperty.SetValue(originalEntity, propertyInfo.GetValue(newEntity, null)); 
     } 
    } 

我調用對象如下:

public IHttpActionResult PutPlayer(int id, PlayerEntity player) 
    { 
     if (player == null) 
     { 
      return NotFound(); 
     } 
     _playerService.Update(player); 

     return Ok(); 
    } 

注:我使用AutoMapper的對象映射,但是我不認爲這是錯誤有關。謝謝。

回答

0

問題是您的方法ApplyChanges複製了太多的屬性。您希望它僅複製標量屬性,即類型爲int,string等的屬性,而不是引用和集合。但是你的方法完成了所有這些。

這會導致LINQ-to-SQL得出結論:PlayerSkills被一個全新的PlayerSkill對象集合取代。所以它會嘗試插入新的。但它也會嘗試孤兒現有的。這會導致PlayerSkill.Skill_ID不能設置爲空的例外。

的解決方案是隻複製標量屬性:

private void ApplyChanges<F, S>(F originalEntity, S newEntity) 
{ 
    var entityType = typeof(F); 
    var entityProperties = entityType.GetProperties(); 
    foreach (var propertyInfo in entityProperties 
     // Filter scalar properties 
     .Where(pi => pi.PropertyType.IsValueType || pi.PropertyType == typeof(string))) 
    { 
     var currentProperty = entityType.GetProperty(propertyInfo.Name); 
     currentProperty.SetValue(originalEntity, propertyInfo.GetValue(newEntity, null)); 
    } 
} 

這會篩選值類型屬性和字符串的屬性(字符串不是值類型,但一類)。