在 Entity Framework 中什么是实体 Entity
在 EF 中一个实体就是程序域中的一个类,它在继承的上下文类中包含在 DbSet<TEntity>
中作为类型属性。EF API 把每一个实体映射到一张表,把实体的每一个属性映射到数据库中的列。
例如,在 school 程序中下面的Student
,StudentAddress
和Grade
是域类。
public class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public DateTime? DateOfBirth { get; set; }
public byte[] Photo { get; set; }
public decimal Height { get; set; }
public float Weight { get; set; }
public StudentAddress StudentAddress { get; set; }
public Grade Grade { get; set; }
}
public partial class StudentAddress
{
public int StudentID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public Student Student { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
public ICollection<Student> Students { get; set; }
}
上面的这些类当它们在上下文类(继承自DbContext
)中被包含在DbSet<TEntity>
中作为属性时,它们就变成了实体,如下所示。
public class SchoolContext : DbContext
{
public SchoolContext()
{
}
public DbSet<Student> Students { get; set; }
public DbSet<StudentAddress> StudentAddresses { get; set; }
public DbSet<Grade> Grades { get; set; }
}
在上面的上下文类中,Students
,StudentAddresses
, 和 Grades
属性的类型 DbSet<TEntity>
被称为实体集。Student
,,StudentAddress
,,和Grade
是实体 (也叫实体类型)。
一个实体(Entity)可以包含两种类型的属性:标量属性(Scalar Properties)和导航属性(Navigation Properties)。
标量属性(Scalar Properties):
基本类型的属性称为标量属性。一个标量属性可以存储实际的数据。一个标量属性可以映射到数据库表的一个列。
导航属性(Navigation Properties):
导航属性代表和另一个实体之间的关系。
有两种类型的导航属性:引用导航(Reference Navigation)和集合导航(Collection Navigation)
引用导航属性(Reference Navigation Property):
如果一个实体中包含一个实体类型的属性,这个属性就叫引用导航属性。它代表多个中的一个。
集合导航属性(Collection Navigation Property):
如果一个实体包含一个集合类型的属性,这个属性就叫集合导航属性。它代表多个中的多个。
下面的图表解释了实体的属性:
实体的类型
Entity Framework 中的实体类型:
在Entity Framework 中有两种实体类型:简单对象实体(POCO Entities)和动态代理实体(Dynamic Proxy Entities)。
简单对象实体(Pain Old CLR Object):
一个简单对象实体是一个类,它不依赖于特定框架的中基类。它和任何 .NET CLR 中的类一样,这就是它被称为简单对象实体的原因。
简单对象实体在 EF 6 和 EF Core 中都被支持。
Entity Data Model 中生成的实体类型的查询,插入,更新和删除中的大多数行为,在简单对象实体(也叫持久无关对象)中是一模一样的。下面是一个 Student 简单对象实体的一个例子。
public class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public DateTime? DateOfBirth { get; set; }
public byte[] Photo { get; set; }
public decimal Height { get; set; }
public float Weight { get; set; }
public StudentAddress StudentAddress { get; set; }
public Grade Grade { get; set; }
}
动态代理实体(Dynamic Proxy Entities):
动态代理是一个封装了简单对象实体的运行时代理类。动态代理实体允许延迟加载(lazy loading)。
注意:只在 EF 6 中支持,在 EF Core 2.0 中暂时不支持。
一个简单对象实体必须满足一下条件才能成为一个简单对象代理:
- 一个简单对象类必须声明成 public 访问。
- 一个简单对象类必须不能是 sealed (在 Visual Basic 是 NotInheritable )。
- 一个简单对象类必须不能是 abstract (在 Visual Basic 是 MustInherit )。
- 每一个导航属性必须声明成 public,virtual。
- 每一个集合属性必须是
ICollection<T>
。 - 在上下文类中 ProxyCreationEnabled 选项不能是 false (默认是 true)。
下面的简单对象实体满足了上面的所有要求,在运行时可以变成一个动态代理实体。
public class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public DateTime? DateOfBirth { get; set; }
public byte[] Photo { get; set; }
public decimal Height { get; set; }
public float Weight { get; set; }
public virtual StudentAddress StudentAddress { get; set; }
public virtual Grade Grade { get; set; }
}
注意:默认情况下,每一个实体的动态代理是打开的。然而,你可以在上下文类中通过设置context.Configuration.ProxyCreationEnabled = false;
来关闭动态代理。
在运行时, EF API 将会为上面的 Student
实体创建一个动态代理的实例。Student
的动态代理类型将会是System.Data.Entity.DynamicProxies.Student
,如下所示:
使用`ObjectContext.GetObjectType()可以找到被动态代理封装在底层的类型,如下所示:
实体状态
Entity States in Entity Framework:
EF API 维持每一个实体声明周期期间的状态。通过上下文对每一个实体执行操作时都会有一个状态。在 EF 6 中,实体的状态用枚举类型System.Data.Entity.EntityState
表示,在 EF Core 中用枚举类型Microsoft.EntityFrameworkCore.EntityState
表示。这些枚举类型有如下值:
- Added
- Modified
- Deleted
- Unchanged
- Detached
一旦上下文从数据库中检索数据,它就会保持所有实体对象的引用,也会保持对实体状态的跟踪维护队实体属性所作的修改。这个特性就叫做改变跟踪(Change Tracking)。
实体状态从 Unchanged 转变成 Modified 状态是唯一个由上下文自动完成情形。所有其它的改变必须显式地使用合适的DbContext
或者 DbSet
中的方法。
EF API 在 context.SaveChanges()
被调用时会根据实体状态创建并执行 INSERT,UPDATE,和 DELETE 命令。它对 Added 状态的实体执行 INSERT 命令,对 Modified 状态的实体执行 UPDATE 命令,对 Deleted 状态的实体执行 DELETE 命令。上下文跟踪 Detached 状态的实体。下面图表解释了状态实体的重要性:
因此,实体状态在 Entity Framework 中扮演了一个很重要的角色。