实体框架多对多插入很好,但没有正确更新

本文关键字:更新 框架 插入 很好 实体 | 更新日期: 2023-09-27 18:15:13

早上好!

Employee和Skill实体之间有一个多对多关系。当我创建一个新的Employee时,我所选择的Skills将毫无问题地添加到数据库中。但是,当我更新Employee时,Employee内容更新,但没有添加/删除任何技能。我看到它们正在被传递到存储库,但它没有更新数据库。

我有以下多对多关系:

public class Employee : BaseEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string JobTitle { get; set; }
    public virtual ICollection<Skill> Skills { get; set; }
}

:

public class Skill : BaseEntity
{
    public string Name { get; set; }
    public virtual ICollection<Employee> Employees { get; set; }
}

我的控制器通过以下方法添加/删除雇员的技能:

public ActionResult Edit(int id, EmployeeEditViewModel viewModel)
{
    try
    {
        if (!ModelState.IsValid)
        {
            viewModel.SkillsList = _skillService.GetAll().ToList();
            return View(viewModel);
        }
        var employee = Mapper.Map<Employee>(viewModel);
        UpdateSkills(employee, viewModel.NewSkills);
        _employeeService.Update(employee);
        return RedirectToAction("Index");
    }
    catch(Exception e)
    {
        ModelState.AddModelError("", e.Message);
        viewModel.SkillsList = _skillService.GetAll().ToList();
        return View(viewModel);
    }
}

    private void UpdateSkills(Employee employee, IEnumerable<int> updatedSkills)
    {
        if (employee.Skills != null)
        {
            var updatedSkillsList = updatedSkills as IList<int> ?? updatedSkills.ToList();
            var addedSkills = updatedSkillsList.Except(employee.Skills.Select(x => x.Id));
            var removedSkills = employee.Skills.Select(x => x.Id).Except(updatedSkillsList);
            addedSkills.ForEach(x => employee.Skills.Add(_skillService.GetById(x)));
            removedSkills.ForEach(x => employee.Skills.Remove(_skillService.GetById(x)));
        }
        else
        {
            employee.Skills = new List<Skill>();
            newSkills.ForEach(x => employee.Skills.Add(_skillService.GetById(x)));
        }
    }

然后用通用存储库插入/更新Employee:

public void Insert(TEntity entity)
{
    if (entity == null)
        throw new ArgumentNullException("entity");
    try
    {
        _dbSet.Add(entity);
        _dbContext.SaveChanges();
    }
    catch (DbEntityValidationException ex)
    {
        ThrowValidationError(ex);
    }
}

    public void Update(TEntity entity)
    {
        if (entity == null)
            throw new ArgumentNullException("entity");
        try
        {
            _dbSet.Attach(entity);
            _dbContext.Entry(entity).State = EntityState.Modified;
            _dbContext.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            ThrowValidationError(ex);
        }
    }

下面是如何从数据上下文调用Employee对象的。

构造函数:

protected readonly NTierApplicationsDataContext _dbContext;
        protected readonly DbSet<TEntity> _dbSet;
        public EfRepository(NTierApplicationsDataContext dbContext)
        {
            _dbContext = dbContext;
            _dbSet = _dbContext.Set<TEntity>();
        } 

下面是查找对象的方法:

public TEntity GetById(int id)
        {
            return _dbSet.Find(id);
        }

实体框架多对多插入很好,但没有正确更新

我认为您必须在编辑技能后更新员工本身,如下所示

private void UpdateSkills(Employee employee, IEnumerable<int> updatedSkills)
{
    if (employee.Skills != null)
    {
        var updatedSkillsList = updatedSkills as IList<int> ?? updatedSkills.ToList();
        var addedSkills = updatedSkillsList.Except(employee.Skills.Select(x => x.Id));
        var removedSkills = employee.Skills.Select(x => x.Id).Except(updatedSkillsList);
        addedSkills.ForEach(x => employee.Skills.Add(_skillService.GetById(x)));
        removedSkills.ForEach(x => employee.Skills.Remove(_skillService.GetById(x)));
         // here 
         _employeeService.Update(employee);
    }
    else
    {
        employee.Skills = new List<Skill>();
        newSkills.ForEach(x => employee.Skills.Add(_skillService.GetById(x)));
    }
}

EDIT: Check Mapping

编辑:

我认为你的实体映射有问题,你可以用另一种方法

public ActionResult Edit(int id, EmployeeEditViewModel viewModel)
{
   try
   {
    if (!ModelState.IsValid)
    {
        viewModel.SkillsList = _skillService.GetAll().ToList();
        return View(viewModel);
    }
    //here your mapper is not attaching the employee to the context
    //var employee = Mapper.Map<Employee>(viewModel);
    you can do this 
    var employee = _employeeService.GetById(viewModel.Id);
    // after that ... update what the user did from the view model except the id as the id won't change
    employee = Mapper.Map<Employee>(viewModel, employee);
    // I think that the mapping have another overload to map to a destination. you can set the setup for the mappnig in the startup to ignore updating Ids        
    UpdateSkills(viewModel.NewSkills);
    _employeeService.Update(employee);
    return RedirectToAction("Index");
}
catch(Exception e)
{
    ModelState.AddModelError("", e.Message);
    viewModel.SkillsList = _skillService.GetAll().ToList();
    return View(viewModel);
}

}