Я чувствую, что должен быть легкий ответ на этот вопрос, но я не могу, похоже, обернуться вокруг него. У меня есть репозиторий, который первоначально был создан в MvcScaffolding tool, поэтому он имеет метод, который выглядит следующим образом:Как правильно пометить объект, уже прикрепленный к контексту, как измененный?
public void InsertOrUpdate(PhysicianSchedule physicianSchedule)
{
if (physicianSchedule.Id == default(int)) {
// New entity
context.PhysicianSchedules.Add(physicianSchedule);
} else {
// Existing entity
context.Entry(physicianSchedule).State = EntityState.Modified;
}
}
Это первоначально работало хорошо отметить, когда график врача объект был совершенно новым, или существует, но необходимо обновить , У меня есть уникальный индекс, настроенный для трех конкретных полей в этой сущности, поскольку у меня не может быть двух разных графиков в файле с одинаковыми значениями для этих полей (в частности, идентификатор врача, идентификатор отдела и дата вступления в силу).
В моем контроллере MVC, я добавил некоторые проверки модели, чтобы убедиться, что кто-то не добавляло новое расписание или редактирования существующего, который будет иметь значение в этих трех областях, которые соответствуют другой записи на файл:
private void ValidateMatchOnFile(PhysicianScheduleViewModel physicianScheduleViewModel)
{
PhysicianSchedule matchingScheduleOnFile = physicianScheduleRepository.Find(physicianScheduleViewModel.PhysicianId,
physicianScheduleViewModel.DepartmentId,
physicianScheduleViewModel.EffectiveDate);
if ((matchingScheduleOnFile != null) && (matchingScheduleOnFile.Id != physicianScheduleViewModel.Id))
{
ModelState.AddModelError("EffectiveDate", "There is already an effective date on file for this physician and department.");
}
}
Вышеуказанные два метода в основном вызывается последовательно при редактировании расписания, поэтому они совместно используют один объект Entity Framework DbContext (через репозиторий). Это, в конечном счете, вызывает мою проблему: при условии, что нет соответствующего графика в файле, отличном от существующего, редактируемого метода ValidateMatchOnFile() привязывает текущий объект планирования врача к контексту EF до в InsertOrUpdate () метод, связанный с этим (через строку, вызывающую context.Entry()). Затем я получаю ожидаемую ошибку InvalidOperationException:
«Объект с тем же ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом».
Что я не знаю, это лучший способ обойти это. Должен ли я изменить способ поиска подходящего (но другого) объекта в файле в методе ValidateMatchOnFile()? Должен ли я посмотреть, будет ли объект, который будет вставлен в InsertOrUpdate(), уже существует в локальном контексте? Что касается второго подхода, я последовал примеру Ladislav's answer to this question и вставил это в мой InsertOrUpdate() метод:
// Check to see if entity was already loaded into the context:
bool entityAlreadyInContext = context.Set<PhysicianSchedule>().Local
.Any(ps => ps.Id == physicianSchedule.Id);
и она отлично работает, чтобы определить, является ли объект действительно существует в местном контексте, но я Не знаю, как переписать часть инструкции IF для определения того, была ли сущность уже прикреплена к контексту или нет.
Я использую ASP.NET MVC 4 и EF5. Спасибо за любую помощь!
Update с моим решением, благодаря Гертам:
Вместо того, чтобы использовать этот метод в DbContext называется Любой() во время вызова InsertOrUpdate(), вместо этого я создал новый метод в моем который проверял существование того, что я искал, без фактического прикрепления соответствующего объекта к моему контексту.Я добавил этот метод в мой репозиторий (имя, по общему признанию, не очень элегантно):
public bool MatchingScheduleDifferentId(int physicianScheduleId, int physicianId, int departmentId, DateTime effectiveDate)
{
bool test = context.PhysicianSchedules.Any(ps => ps.Id != physicianScheduleId && ps.PhysicianId == physicianId && ps.DepartmentId == departmentId && ps.EffectiveDate == effectiveDate);
return test;
}
И тогда я упростил логику в методе проверки в моем контроллере MVC это:
public void ValidateMatchOnFile(PhysicianScheduleViewModel physicianScheduleViewModel)
{
bool matchingScheduleOnFile = physicianScheduleRepository.MatchingScheduleDifferentId(physicianScheduleViewModel.Id,
physicianScheduleViewModel.PhysicianId,
physicianScheduleViewModel.DepartmentId,
physicianScheduleViewModel.EffectiveDate);
if (matchingScheduleOnFile == true)
{
ModelState.AddModelError("EffectiveDate", "There is already an effective date on file for this physician and department.");
}
}
Интересно - я даже не думал об использовании Any() в отношении проверки, которую я выполняю до вызова метода InsertOrUpdate(). Вместо того, чтобы называть ваш предложенный новый метод в моем репозитории «Any», я пошел с Exists(), который, как я вижу, сделал другой человек, основываясь на других подобных вопросах. И он отлично поработал - спасибо Герту! Я обновляю свой вопрос своим рабочим решением. – Derek