2013-05-24 2 views
0

Я чувствую, что должен быть легкий ответ на этот вопрос, но я не могу, похоже, обернуться вокруг него. У меня есть репозиторий, который первоначально был создан в 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."); 
     } 
    } 

ответ

1

Я бы добавить метод в репозиторий: Any, так что вы можете сделать

physicianScheduleRepository.Any(... your parameters ...); 

Внутри метод выполняет

return context.PhysicianSchedules.Any(s => s.Id == physicianId 
             && s. .... the other crietria); 

Это не приносит какой-либо объект в контекст и отправляет только булев (бит) по строке.

+0

Интересно - я даже не думал об использовании Any() в отношении проверки, которую я выполняю до вызова метода InsertOrUpdate(). Вместо того, чтобы называть ваш предложенный новый метод в моем репозитории «Any», я пошел с Exists(), который, как я вижу, сделал другой человек, основываясь на других подобных вопросах. И он отлично поработал - спасибо Герту! Я обновляю свой вопрос своим рабочим решением. – Derek

Смежные вопросы