在上一篇文章中,学习了在有连接场景中EF Core的ChangeTracker
如何自动更改EntityState
。在本篇文章中,我们将学习在Entity Framework Core中无连接方案中的根实体和子实体上的不同方法的行为和跟踪图。
实体框架核心提供以下不同的方法,它们不仅将实体附加到上下文,还更改EntityState无连接
的实体图中的每个实体:
- Attach()
- Entry()
- Add()
- Update()
- Remove()
让我们看看上述方法用Entity Framework Core 2.x中的跟踪图如何中更改每个实体的 EntityState 。
Attach()方法
DbContext.Attach()
和DbSet.Attach()
方法附加指定无连接的实体图,并开始跟踪它。它们返回一个实例EntityEntry
,用于分配适当的实例EntityState
。
以下示例演示了DbContext.Attach()
方法对EntityState
图中每个实体的行为。
public static void Main()
{
var stud = new Student() { //Root entity (empty key)
Name = "Bill",
Address = new StudentAddress() //Child entity (with key value)
{
StudentAddressId = 1,
City = "Seattle",
Country = "USA"
},
StudentCourses = new List<StudentCourse>() {
new StudentCourse(){ Course = new Course(){ CourseName = "Machine Language" } },//Child entity (empty key)
new StudentCourse(){ Course = new Course(){ CourseId = 2 } } //Child entity (with key value)
}
};
var context = new SchoolContext();
context.Attach(stud).State = EntityState.Added;
DisplayStates(context.ChangeTracker.Entries());
}
private static void DisplayStates(IEnumerable<EntityEntry> entries)
{
foreach (var entry in entries)
{
Console.WriteLine($"Entity: {entry.Entity.GetType().Name},
State: {entry.State.ToString()} ");
}
}
Output:
Entity: Student, State: Added
Entity: StudentAddress, State: Unchanged
Entity: StudentCourse, State: Added
Entity: Course, State: Added
Entity: StudentCourse, State: Added
Entity: Course, State: Unchanged
在上面的示例中,stud
是Student
实体图的实例,其包括StudentAddress
和StudentCourse
实体的引用。 context.Attach(stud).State = EntityState.Added
将stud
实体图附加到上下文并为其设置已添加状态。
的Attach()
添加方法设置EntityState
到根实体(在这种情况下,Student
不管其是否包含密钥值或没有)。如果子实体包含键值,则它将被标记为未更改,否则将标记为已添加。上面示例的输出显示Student
实体已添加EntityState
,具有非空键值的子实体具有未更改EntityState
,具有空键值的子实体具有已添加状态。
下表列出了Attach()
在设置不同EntityState
的断开连接的实体图时方法的行为。
Attach() | 具有Key的根实体 | 具有Empty或CLR默认值的Root实体 | 具有键值的子实体 | 具有空或CLR默认值的子实体 |
---|---|---|---|---|
context.Attach(entityGraph).State = EntityState.Added | Added | Added | Unchanged | Added |
context.Attach(entityGraph).State = EntityState.Modified | Modified | Exception | Unchanged | Added |
context.Attach(entityGraph).State = EntityState.Deleted | Deleted | Exception | Unchanged | Added |
Entry()方法
DbContext.Entry()
与先前的EF 6.x相比, 该方法在Entity Framework Core中的行为有所不同。请考虑以下示例:
Output:
Entity: Student, State: Modified
在上面的示例中,context.Entry(student).State = EntityState.Modified
将实体附加到上下文并将指定的EntityState
(在本例中为Modified)应用于根实体,而不管它是否包含Key属性值。它会忽略图表中的所有子实体,并且不会附加或设置它们EntityState
。
下表列出了该DbContext.Entry()
方法的不同行为。
使用Entry() 设置实体状态 | 根实体有Key | 具有Empty或CLR默认值的Root实体 | 不管子实体有无Key |
---|---|---|---|
context.Entry(entityGraph).State = EntityState.Added | Added | Added | Ignored |
context.Entry(entityGraph).State = EntityState.Modified | Modified | Modified | Ignored |
context.Entry(entityGraph).State = EntityState.Deleted | Deleted | Deleted | Ignored |
Add()方法
该DbContext.Add
和DbSet.Add
方法附加实体图来添加上下文并设置EntityState
到根和子实体,不论他们是否有键值与否。
var student = new Student() { //Root entity (with key value)
StudentId = 1,
Name = "Bill",
Address = new StudentAddress() //Child entity (with key value)
{
StudentAddressId = 1,
City = "Seattle",
Country = "USA"
},
StudentCourses = new List<StudentCourse>() {
new StudentCourse(){ Course = new Course(){ CourseName="Machine Language" } },//Child entity (empty key)
new StudentCourse(){ Course = new Course(){ CourseId=2 } } //Child entity (with key value)
}
};
var context = new SchoolContext();
context.Students.Add(student);
DisplayStates(context.ChangeTracker.Entries());
Output:
Entity: Student, State: Added
Entity: StudentAddress, State: Added
Entity: StudentCourse, State: Added
Entity: Course, State: Added
Entity: StudentCourse, State: Added
Entity: Course, State: Added
下表列出了使用DbContext.Add
或DbSet.Add
方法的图中每个实体的可能EntityState 。
方法 | 不管根实体有无Key | 不管子实体有无Key |
---|---|---|
DbContext.Add(entityGraph) or DbSet.Add(entityGraph) | Added | Added |
Update()方法
DbContext.Update()
和DbSet.Update()
方法附加的实体图形到上下文,并设置EntityState
这取决于它是否包含一个键属性值或者未每个实体中的曲线图。请考虑以下示例。
var student = new Student() { //Root entity (with key value)
StudentId = 1,
Name = "Bill",
Address = new StudentAddress() //Child entity (with key value)
{
StudentAddressId = 1,
City = "Seattle",
Country = "USA"
},
StudentCourses = new List<StudentCourse>() {
new StudentCourse(){ Course = new Course(){ CourseName="Machine Language" } },//Child entity (empty key)
new StudentCourse(){ Course = new Course(){ CourseId=2 } } //Child entity (with key value)
}
};
var context = new SchoolContext();
context.Update(student);
DisplayStates(context.ChangeTracker.Entries());
Output:
Entity: Student, State: Modified
Entity: StudentAddress, State: Modified
Entity: StudentCourse, State: Added
Entity: Course, State: Added
Entity: StudentCourse, State: Added
Entity: Course, State: Modified
在上面的示例中,该Update()
方法将Modified状态应用于包含非空键属性值的实体,并将Added状态应用于包含空或默认CLR键值的实体,而不管它们是根实体还是子实体。
Update() | 具有键值的根实体 | 具有Empty或CLR默认值的Root实体 | 具有键值的子实体 | 具有空键值的子实体 |
---|---|---|---|---|
DbContext.Update(entityGraph) or DbSet.Update(entityGraph) | Modified | Added | Modified | Added |
Remove()方法
该DbContext.Remove()
和DbSet.Remove()
方法已删除设置EntityState
到根实体。
var student = new Student() { //Root entity (with key value)
StudentId = 1,
Name = "Bill",
Address = new StudentAddress() //Child entity (with key value)
{
StudentAddressId = 1,
City = "Seattle",
Country = "USA"
},
StudentCourses = new List<StudentCourse>() {
new StudentCourse(){ Course = new Course(){ CourseName="Machine Language" } },//Child entity (empty key)
new StudentCourse(){ Course = new Course(){ CourseId=2 } }
}
};
var context = new SchoolContext();
context.Remove(student);
DisplayStates(context.ChangeTracker.Entries());
Output:
Entity: Student, State: Deleted
Entity: StudentAddress, State: Unchanged
Entity: StudentCourse, State: Added
Entity: Course, State: Added
Entity: StudentCourse, State: Added
Entity: Course, State: Unchanged
下表列出了每个实体Remove()
上方法的行为EntityState
。
Remove() | 具有键值的根实体 | 具有Empty或CLR默认值的Root实体 | 具有键值的子实体 | 具有空键值的子实体 |
---|---|---|---|---|
DbContext.Remove(entityGraph) or DbSet.Remove(entityGraph) | Deleted | Exception | Unchanged | Added |
因此,在EF Core中使用上述方法时要小心。
ChangeTracker.TrackGraph()
在下一章中 了解处理实体图中每个实体的方法。