Entity Framework Core系列教程-21-断开模式的实体图(Entity Graph)

Entity Framework Core使用断开模式的实体图(Entity Graph)

在上一章中,您学习了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是学生实体图的实例,其中包括对StudentAddress和StudentCourse实体的引用。 context.Attach(stud).State = EntityState.Added会将图钉实体图附加到上下文,并为其设置Added状态。
Attach()方法将添加的EntityState设置为根实体(在本例中为Student),无论其是否包含Key值。如果子实体包含键值,则它将被标记为“不变”,否则将被标记为“已添加”。上面示例的输出显示,学生实体具有Added EntityState,具有非空键值的子实体具有Unchanged EntityState,而具有空键值的子实体具有Added状态。
下表列出了在为断开连接的实体图设置其他EntityState时,Attach(方法的行为。

Attach() 具有键值的根实体 具有空值或CLR默认值的根实体 具有键值的子实体 空实体或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()

与以前的EF 6.x相比,DbContext.Entry(方法在Entity Framework Core中的行为有所不同。考虑以下示例:

var student = 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.Entry(student).State = EntityState.Modified;

DisplayStates(context.ChangeTracker.Entries());
Output:
Entity: Student, State: Modified

在上面的示例中,context.Entry(student).State = EntityState.Modified将实体附加到上下文,并将指定的EntityState(在本例中为Modified)应用于根实体,而不管其是否包含Key属性值或不。它会忽略图中的所有子实体,并且不会附加或设置其EntityState。
下表列出了DbContext.Entry(方法的不同行为。

使用Entry()设置EntityState 具有键值的根实体 具有空值或CLR默认值的根实体 有/没有键值的子实体
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方法将实体图附加到上下文,并将“ Added 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。

方法 具有/不具有键值的根实体 有/没有键值的子实体
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() 具有键值的根实体 具有空值或CLR默认值的根实体 具有键值的子实体 空键值的子实体
DbContext.Update(entityGraph) or DbSet.Update(entityGraph) Modified Added Modified Added

Remove()

DbContext.Remove(和DbSet.Remove(方法将Deleted 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.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

下表列出了每个实体的EntityState上Remove(方法的行为。

Remove() 具有键值的根实体 具有空值或CLR默认值的根实体 具有键值的子实体 空键值的子实体
DbContext.Remove(entityGraph) or DbSet.Remove(entityGraph) Deleted Exception Unchanged Added

因此,在EF Core中使用上述方法时要小心。
在下一章中,将学习有关如何处理实体图中每个实体的ChangeTracker.TrackGraph(方法。

原文地址:https://www.cnblogs.com/AlexanderZhao/p/12878802.html