在EF 6中附加未被跟踪实体的方法
在这里,您将了解Entity Framework 6.x中将断开连接的实体附加到上下文的不同方法。
所谓断开连接的实体是指: 一个普通的POCO类,其并未被纳入EF的DbContext上下文管理范围内,即DbContext无法跟踪其状态。
在断开连接的场景下保存实体与在已连接的场景下保存实体不同。当我们得到一个不连接的实体图或者甚至是单个不连接的实体时,我们需要做两件事。首先,我们需要将实体附加到新的上下文实例中,并使上下文知道这些实体。其次,手动为每个实体设置适当的EntityState,因为实例不知道在断开连接的实体上执行的任何操作,因此它不能自动应用适当的EntityState。
下图说明了这个过程。
Entity Framework提供了以下方法,将断开连接的实体附加到上下文,并将EntityState设置为实体图中的每个实体。
- DbContext.Entry()
- DbSet.Add()
- DbSet.Attach()
DbContext.Entry()
DbContext类的Entry()方法返回指定实体的DbEntityEntry实例。DbEntityEntry对象提供了关于指定实体的各种信息,以及对实体执行操作的能力。最重要的是,我们可以使用State属性更改指定实体的EntityState,如下所示。
context.Entry(entity).state = EntityState.Added/Modified/Deleted
Entry方法将整个实体图附加到上下文,并将指定的状态附加到父实体,还将不同的EntityState设置到其他实体。考虑下面的例子。
var student = new Student() { //Root entity (empty key)
StudentName = "Bill",
StandardId = 1,
Standard = new Standard() //Child entity (with key value)
{
StandardId = 1,
StandardName = "Grade 1"
},
Courses = new List<Course>() {
new Course(){ CourseName = "Machine Language" }, //Child entity (empty key)
new Course(){ CourseId = 2 } //Child entity (with key value)
}
};
using (var context = new SchoolDBEntities())
{
context.Entry(student).State = EntityState.Added; //设置student实体状态为Added
foreach (var entity in context.ChangeTracker.Entries()){ //遍历当前上下文实例中跟踪的所有实体
Console.WriteLine("{0}: {1}", entity.Entity.GetType().Name, entity.State);
}
}
Output:
Student: Added
Standard: Added
Course: Added
Course: Added
在上面的例子中,Studnet实体图包括Standard和Course实体。context.Entry(student).State = EntityState.Added;为父实体以及所有其他子实体设置Added状态,而不管子实体是否包含空键值。因此,建议谨慎使用Entry()方法。
下表列出了Entry()方法的方法。
父Entity 状态 | Entity子实体状态 |
---|---|
Added | Added |
Modified | Unchanged |
Deleted | All child entities will be null |
DbSet.Add()
DbSet.Add()方法将整个实体图附加到一个上下文中,并自动将Added状态应用到所有实体。
//未被纳入上下文管理的实体
Student disconnectedStudent = new Student() { StudentName = "New Student" };
disconnectedStudent.StudentAddress = new StudentAddress() { Address1 = "Address", City = "City1" };
using (var context = new SchoolDBEntities())
{
//DbSet.Add()方法将整个实体图附加到一个上下文中,并自动将Added状态应用到所有实体。
context.Students.Add(disconnectedStudent);
// 获取DbEntityEntry实例,检查指定实体的EntityState
var studentEntry = context.Entry(disconnectedStudent);
var addressEntry = context.Entry(disconnectedStudent.StudentAddress);
Console.WriteLine("Student: {0}", studentEntry.State);
Console.WriteLine("StudentAddress: {0}", addressEntry.State);
}
Output:
Student: Added
StudentAddress: Added
DbSet.Add()方法将整个实体图附加到一个上下文,并将Added 状态附加到每个实体。调用context.Savechanges()将为所有实体执行INSERT命令,这将在适当的数据库表中插入新记录。
DbSet.Attach()
DbSet.Attach()方法将整个实体图附加到具有Unchanged实体状态的新上下文。
//未被纳入上下文管理的实体
Student disconnectedStudent = new Student() { StudentName = "New Student" };
disconnectedStudent.StudentAddress = new StudentAddress() { Address1 = "Address", City = "City1" };
using (var context = new SchoolDBEntities())
{
context.Students.Attach(disconnectedStudent);
// 获取DbEntityEntry实例,检查指定实体的EntityState
var studentEntry = context.Entry(disconnectedStudent);
var addressEntry = context.Entry(disconnectedStudent.StudentAddress);
Console.WriteLine("Student: {0}",studentEntry.State);
Console.WriteLine("StudentAddress: {0}",addressEntry.State);
}
Output:
Student: Unchanged
StudentAddress: Unchanged
参考
https://www.entityframeworktutorial.net/
https://msdn.microsoft.com/