Я должен предположить, что "dbo.CourseTypeCourses" является промежуточной таблицей, которая содержит оба ключа Cources и CourceResources, и что вы действительно пытаетесь добавить запись, которая уже существует.
Обратите внимание, что действие отсоединениявы делаете на CourceResources в методе GET, не пропускаете конец этого метода, потому что вы не сохраняете никаких изменений в вашем объекте db (и, честно говоря, вы вообще не должны идти по этому пути).Поэтому, когда вы получаете объекты базы данных в вашем методе POST, вы получаете их такими, какими они были в начале.
Чтобы объяснить это подробнее, обратите внимание, что класс Controller реализует интерфейс IDisposable, располагающий экземпляр в конце каждого вызова и запускающий конструктор по умолчанию в начале каждого вызова.Таким образом, любые изменения свойств вашего контроллера (то есть объекта db) не проходят конец вызова.Ваш объект db инициализируется при каждом вызове вместе с контроллером.
Способ выполнить то, что вы хотите сделать, на мой взгляд, намного проще:
- Вам не нужно вносить какие-либо изменения в ваши объекты БД в методе GET.
- В вашем методе POST получите курс из БД (как и вы), , включая CourseResources.Очистите все предметы из CourseResources и добавьте все новые (как вы)
Так что попробуйте что-то вроде следующего:
public ActionResult Edit(int? id)
{
if (id == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
Course course = db.Courses
.Include(x => x.CourseResources)
.Where(x => x.Id == id)
.AsNoTracking()
.FirstOrDefault();
if (course == null)
return HttpNotFound();
//db.Detach(course.CourseResources);
CourseVm courseVm = new CourseVm()
{
Course = course,
// other properties
};
return View(courseVm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(CourseVm courseVm)
{
if (ModelState.IsValid)
{
IList<int> rsIds = courseVm.Course.CourseResources.Select(x => x.Id).ToList();
Course c = db.Courses
.Include(x => x.CourseResources)
.Where(x => x.Id == id)
.AsNoTracking()
.FirstOrDefault();
if (c.IsNotNull())
{
c.CourseResources.Clear();
foreach (var resourceId in rsIds)
{
var rs = db.CourseResources.SingleOrDefault(x => x.Id == resourceId);
if (rs.IsNotNull())
c.CourseResources.Add(rs);
}
db.Entry(c).State = EntityState.Modified;
db.SaveChanges();
}
return RedirectToAction("Index");
}
Веселое кодирование!