Обновление связанных сущностей отношениями один-ко-многим в ядре инфраструктуры сущностей - PullRequest
0 голосов
/ 01 марта 2019

У меня есть отношение один ко многим, которое я пытаюсь обновить, но получаю сообщение об ошибке

Операция над базой данных, как ожидается, повлияет на 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);
}

У кого-нибудь есть идеи, как это сделать?

1 Ответ

0 голосов
/ 08 марта 2019

Я наконец достиг прогресса, прочитав о том, как работает обновление.В основном, как уже упоминалось здесь , и это выпуск .При вызове метода Update состояние всей сущности, включая все достижимые сущности через свойства навигации, помечается как измененное.Если вы пытаетесь добавить бенефициаров к существующему сотруднику, SaveChanges () выбрасывает, так как он ожидает изменения записи с предоставленным первичным ключом (ключами), но не находит ни одной в базе данных.Метод обновления казался не лучшим кандидатом.

Я решил сделать метод Update из базы репозитория переопределяемым в EmployeeRepository, как показано ниже

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

Я считаю, что этот ответ можно улучшить или настроить дляудовлетворить конкретные ситуации.Например, кроме очистки постоянной коллекции, можно выбрать обновление

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...