我觉得应该有一个简单的答案,但我似乎无法完全理解它。我有一个最初由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;
}
}
这最初很好地说明了医生计划实体是全新的还是现有的,但需要更新。我为此实体中的三个特定字段设置了唯一索引,因为我不能在文件中有两个不同的日程表,这些字段具有相同的值(特别是医生ID,部门ID和生效日期)。 / p>
在我的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语句的 else 部分以反映实体是否具有已经被附加到上下文中。
我正在使用ASP.NET MVC 4和EF5。谢谢你的帮助!
使用我的解决方案进行更新,感谢Gert:
我没有尝试在InsertOrUpdate()调用期间在DbContext中使用名为Any()的方法,而是在我的存储库中创建了一个新方法,用于检查我正在查找的内容,而不实际附加匹配的实体在我的背景下。我将这个方法添加到我的存储库(这个名称肯定不是很优雅):
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.");
}
}
答案 0 :(得分:1)
我会在您的存储库中添加一个方法:Any
,以便您可以
physicianScheduleRepository.Any( ... your parameters ...);
在里面,该方法执行
return context.PhysicianSchedules.Any(s => s.Id == physicianId
&& s. .... the other crietria);
这不会将任何实体提取到上下文中,只会在该行上发送一个布尔值(位)。