编辑:我选择的解决方案可能不是最好的,但绝对有效。我将在下周完成我的代码(一旦这个项目完成),当我理解出了什么问题时,我会更新我的问题。
我正在使用带有实体5的ASP.NET MVC 4框架。以下是一些代码:
要在数据库中实例化和保存(新)的类:
public class ClassCancellation
{
[Key]
public int Id { get; set; }
public Faculty Professor { get; set; }
public DateTime CancelledOn { get; set; }
public Course Course { get; set; }
[Required]
public ClassDate ClassCancelled { get; set; }
public Message CancellationMessage { get; set; }
[Required]
public List<Student> Students { get; set; }
}
它是从名为CancellationFull
的视图模型(使用AutoMapper)映射的:
public class CancellationForList
{
[Key]
public int Id { get; set; }
public CourseForList Course { get; set; }
public ClassDateForList ClassCancelled { get; set; }
}
public class CancellationFull : CancellationForList
{
public CancellationFull()
{
this.Students = new List<StudentForList>();
}
public FacultyForList Professor { get; set; }
public MessageForList CancellationMessage { get; set; }
public DateTime CancelledOn { get; set; }
public List<StudentForList> Students { get; set; }
}
这是将CancellationFull
转换为ClassCancellation
然后将其保存到数据库的repo方法:
public CancellationFull createClassCancellation(CancellationFull c)
{
ClassCancellation newCancellation = Mapper.Map<ClassCancellation>(c);
dc.ClassCancellations.Add(newCancellation);
dc.SaveChanges();
return Mapper.Map<CancellationFull>(dc.ClassCancellations.FirstOrDefault(cc => cc.Id == newCancellation.Id));
}
为什么,为了爱上帝为什么,当提供每个现有实体对应物的Faculty
(主键)时,数据库是否为Course
和Id
创建了新对象?它也可能对Student
个对象做同样的事情,但我没有仔细看过。
在ClassCancellation
实例保存到数据库之前,调试器显示类型Professor
的属性Faculty
和类型Course
的{{1}}具有正确的属性Course
主键 - 即我尝试使用对新ClassCancellation
对象的引用更新的那些类型的现有实体的主键。
让我疯了。随意请求澄清!
编辑:
以下是从表单数据构建CancellationFull
视图模型的逻辑,以及从各自的存储库中检索到的现有对象的视图模型:
newCancellation = new CancellationFull();
newCancellation.CancelledOn = DateTime.Now;
newCancellation.ClassCancelled = repoClass.getClassDateForListById(Int32.Parse(classIds[i]));
newCancellation.Course = repoCourse.getForList(newCancellation.ClassCancelled.Course.Id);
newCancellation.CancellationMessage = repoMessage.getMessageForList(newMessage.Id);
newCancellation.Professor = repoFac.getFacultyForList((int)Session["facId"]);
var students = repoStudent.getStudentsForListByCourse(newCancellation.Course.Id);
foreach ( var student in students )
{
newCancellation.Students.Add(student);
}
repoCancellation.createClassCancellation(newCancellation);
以下是其中一个repo方法的示例(其余的非常相似):
public CourseForList getForList(int? id)
{
return Mapper.Map<CourseForList>(dc.Courses.FirstOrDefault(c => c.Id == id));
}
答案 0 :(得分:3)
我发现最简单的解决方案是更新模型,清除任何相关实体,然后重新添加它们。
即:
newCancellation.Students.Clear();
foreach ( var student in students )
{
newCancellation.Students.Add(student);
}
答案 1 :(得分:2)
尝试使用Attach()
代替Add()
dc.ClassCancellations.Attach(newCancellation);
dc.SaveChanges();
Add()
用于数据库中尚不存在的新对象。 Attach()
用于创建与数据库中已存在的实体的关系。
修改强>
如果没有看到您的代码,我建议您附加的最佳解决方案是创建一个&#39; stub&#39;实例,然后将其附加到您的newCancellation
:
var existingCourse = new Course{ Id = newCancellation.ClassCancelled.Course.Id };
db.Courses.Attach(existingCourse);
newCancellation.Course = existingCourse;
答案 2 :(得分:1)
问题在于您有多个上下文或工作单元。将newCancellation添加到dc上下文时,它还会在对象图中添加未在dc上下文中跟踪的任何相关实体。我认为你最好的选择是:
dc.ClassCancellations.Add(newCancellation);
dc.Entry(newCancellation.Course).State = EntityState.Unchanged;
dc.Entry(newCancellation.Faculty).State = EntityState.Unchanged;
有关说明和其他选项,请参阅Julie Lerman's article on this issue。
在我看来,EF应该识别具有自动编号密钥的实体,如果分配了密钥则不插入它们。