【问题标题】:Updating connected entities with one-to-many relationships in entity framework core在实体框架核心中更新具有一对多关系的连接实体
【发布时间】:2019-03-01 06:44:46
【问题描述】:

我有一个一对多的关系,我正在尝试更新但收到错误

数据库操作预计会影响 1 行,但实际上会影响 0 行。自加载实体以来,数据可能已被修改或删除。有关理解和处理乐观并发异常的信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=527962

更新

只要受益人集合没有被更改或更新,更新方法将一直有效。

代码看起来像

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }

    private readonly List<Beneficiary> _beneficiaries;
    public IEnumerable<Beneficiary> Beneficiaries => _beneficiaries;

    public void AddBeneficiary(string name)
    {
        var beneficiary = new Beneficiary(Id, name);
        _beneficiaries.Add(beneficiary);
    }
}

public sealed class Beneficiary
{
    public int Id { get; set; }
    public int EmployeeId { get; private set; }
    public string Name { get; private set; }

    public Beneficiary(int employeeId, string name)
    {
        Name = name;
        EmployeeId = employeeId;
    }
}

//Extracted from repo method
public void Update(TEntity entity)
{
    if (entity != null)
        _dbSet.Update(entity);
}

// Extracted Actual update from application service
if (incomingEmployee.Beneficiaries.Any())
{
    if (employeeFromStore.Beneficiaries.Any())
    {
        employeeFromStore.Beneficiaries.ToList()
            .ForEach(existingBeneficiary => 
        employeeFromStore.RemoveBeneficiary(existingBeneficiary)); //Method skipped for brevity

        //Tried calling this too
        //_employeeRepository.UnitOfWork.SaveChanges();
    }

    incomingEmployee.Beneficiaries.ToList().ForEach(beneficiary =>
    {
        employeeFromStore.AddBeneficiary(beneficiary.Name);
    });
}

_employeeRepository.Update(employeeFromStore);
_employeeRepository.UnitOfWork.SaveChanges();

我觉得问题在于跟踪器如何处理导航属性集合的更新,但我可能错了。

我还尝试使用更改跟踪器通过如下方法进行更新

public void ApplyCurrentValues<TEntity>(TEntity original, TEntity current)
        where TEntity : class
{
    //if it is not attached, attach original and set current values
    base.Entry<TEntity>(original).CurrentValues.SetValues(current);
}

有人知道怎么做吗?

【问题讨论】:

    标签: c# entity-framework-core


    【解决方案1】:

    在阅读了更新的工作原理后,我终于取得了进展。基本上就像提到的here ,还有这个issue。当调用 Update 方法时,整个实体的状态(包括通过导航属性可到达的所有实体)被标记为已修改。 如果您尝试将受益人添加到现有员工,SaveChanges() 将抛出,因为它希望使用提供的主键修改记录,但在数据库中找不到。更新方法似乎不是最佳选择。

    我选择在 EmployeeRepository 中将存储库库中的 Update 方法设置为可覆盖,如下所示

    //Update method in the repository base
    //Made method virtual to enable overriding
    public virtual void Update(TEntity entity)
    {
        if (entity != null)
            _dbSet.Update(entity);
    }
    
    //Update method from EmployeeRepository
    public override void Update(Employee employee)
    {
        var employeeFromStore = _unitOfWork.Employees.Where(p => p.Id == employee.Id)
            .Include(p => p.Beneficiaries)
            .SingleOrDefault();
    
        if (employeeFromStore != null)
        {
            context.Entry(employeeFromStore).CurrentValues.SetValues(employee);
    
            //Replacing the whole collection
            foreach (var beneficiary in employeeFromStore.Beneficiaries)
            {
                if (employee.Beneficiaries.Any())
                    context.Entry(beneficiary).State = EntityState.Deleted;
            }
    
            //Adding new collection
            foreach (var beneficiaryToAdd in employee.Beneficiaries)
            {
                var newBeneficiary = new Beneficiary(beneficiaryToAdd.EmployeeId, beneficiaryToAdd.Name);
    
                employeeFromStore.AddBeneficiary(newBeneficiary.Name);
            }
        }
    }
    

    我相信这个答案可以改进或调整以适应特定情况。例如,除了清除持久化集合之外,还可以选择更新

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-11
      • 2021-12-04
      • 2021-05-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多