实体框架多对多插入很好,但没有正确更新
本文关键字:更新 框架 插入 很好 实体 | 更新日期: 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);
}
}