Linq to SQL 通用存储库模式更新问题

本文关键字:模式 更新 新问题 存储 to SQL Linq | 更新日期: 2023-09-27 18:36:40

我有一个奇怪的问题。我正在使用通用存储库模式和Linq to SQL。我在作为dbml生成的对象的对象之间有很多关系,这就是问题所在。我在尝试更新播放器对象时收到错误。当我尝试更新玩家技能名称时发生错误。这是我得到的例外:

System.Data.Linq 中发生类型为"System.InvalidOperationException"的异常.dll但未在用户代码中处理

附加信息:尝试删除技能与玩家技能之间的关系。但是,关系的外键之一 (PlayerSkill.Skill_ID) 不能设置为 null。

下面是更新方法。

 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);
    }

存储库上的添加或更新方法:

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);
        }
    }

数据LINQ 层上的更新方法

public void Update(TEntity entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity");
        }
        var original = GetById(GetPrimaryKeyValue(entity));
        ApplyChanges(original, entity);
        _context.SubmitChanges();
    }

最后;应用更改

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();
    }

注意:我使用自动映射器来映射对象,但我认为这与错误无关。谢谢。

Linq to SQL 通用存储库模式更新问题

问题是您的方法ApplyChanges复制了太多属性。您希望它仅复制标量属性,即 intstring 等类型的属性,而不是引用和集合。但是你的方法可以做到所有这些。

这会导致 LINQ-to-SQL 得出结论,PlayerSkills被全新的PlayerSkill对象集合所取代。所以它会尝试插入新的。但它也会试图孤立现有的。这会导致PlayerSkill.Skill_ID不能设置为 null 的异常。

解决方案是仅复制标量属性:

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));
    }
}
这将筛选值类型属性

和字符串属性(字符串不是值类型,而是类)。