一、概述
模型中的每个实体类型都有一组属性,EF Core将从数据库中读取和写入这些属性。如果使用的是关系数据库,实体属性将映射到表列。
二、已包含和已排除的属性
按照约定,所有具有Getter
和Setter
的公共属性都将包含在模型中。
- 排除特定属性
public class Blog { public int BlogId { get; set; } public string Url { get; set; } [NotMapped] public DateTime LoadedFromDatabase { get; set; } }
- 排除Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Ignore(b => b.LoadedFromDatabase); }
三、别名
按照约定,使用关系数据库时,实体属性将映射到与属性同名的表列。如果希望配置具有不同名称的列,可以按以下代码片段进行操作:
- 别名属性
public class Blog { [Column("blog_id")] public int BlogId { get; set; } public string Url { get; set; } }
- 别名Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(b => b.BlogId) .HasColumnName("blog_id"); }
四、列数据类型
使用关系数据库时,数据库提供程序会根据属性的 .NET 类型选择数据类型。 它还会考虑其他元数据。例如配置的最大度,属性是否主键的一部分等等。
如,SQL Server将DateTime属性映射到datetime2(7)列,将string属性映射到nvarchar(max)列(或对于用作键的属性,映射到nvarchar(450))。
还可以配置列以指定列的确切数据类型。 例如,以下代码将 Url 配置为非 unicode 字符串,其最大长度为 200,并将 Rating 配置为十进制,其精度为 5,小数位数为 2:
- 列数据类型属性
public class Blog { public int BlogId { get; set; } [Column(TypeName = "varchar(200)")] public string Url { get; set; } [Column(TypeName = "decimal(5, 2)")] public decimal Rating { get; set; } }
- 列数据类型Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>(eb => { eb.Property(b => b.Url).HasColumnType("varchar(200)"); eb.Property(b => b.Rating).HasColumnType("decimal(5, 2)"); }); }
五、最大长度
配置最大长度可向数据库提供程序提供有关为给定属性选择适当列数据类型的提示。 最大长度仅适用于数组数据类型,如 string
和 byte[]
。
- 最大长度属性
public class Blog { public int BlogId { get; set; } [MaxLength(500)] public string Url { get; set; } }
- 最大长度Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(b => b.Url) .HasMaxLength(500); }
在向提供程序传递数据之前,实体框架不会执行任何最大长度的验证。而是由提供程序或数据存储根据情况进行验证。 例如,当面向 SQL Server 时,超过最大长度将导致异常,因为基础列的数据类型不允许存储多余的数据。
五、精度和小数位数
某些关系数据类型支持精度和小数位数 Facet,它们用于控制可以存储哪些值,以及列需要多少存储。 哪些数据类型支持精度和小数位数取决于数据库,但在大多数数据库中,decimal 和 DateTime 类型支持这些 Facet。 对于 decimal 属性,精度用于定义表示列将包含的任何值所需的最大位数,小数位数用于定义所需的最大小数位数。 对于 DateTime 属性,精度用于定义表示秒的小数部分所需的最大位数,不使用小数位数。
在以下示例中,将 Score 属性配置为精度为 14 和小数位数为 2 将导致在 SQL Server 上创建 decimal(14,2) 类型的列,将 LastUpdated 属性配置为精度为 3 将导致创建 datetime2(3) 类型的列:
- 属性
public class Blog { public int BlogId { get; set; } [Precision(14, 2)] public decimal Score { get; set; } [Precision(3)] public DateTime LastUpdated { get; set; } }
- Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(b => b.Score) .HasPrecision(14, 2); modelBuilder.Entity<Blog>() .Property(b => b.LastUpdated) .HasPrecision(3); }
六、Unicode
在某些关系数据库中,存在不同的类型来表示Unicode和非Unicode文本数据。例如:在SQL Server中,nvarchar(x)用于表示UTF-16格式的Unicode数据,而varchar(x)用于表示非Unicode数据。对于不支持此概念的数据库,配置此概念将不起作用。
默认情况下,文本属性配置为Unicode。可以将列配置为非Unicode,如下所示:
- 属性
public class Book { public int Id { get; set; } public string Title { get; set; } [Unicode(false)] [MaxLength(22)] public string Isbn { get; set; } }
- Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Book>() .Property(b => b.Isbn) .IsUnicode(false); }
六、必需和可选属性
如果属性包含 null
是有效的,则该属性被视为可选属性。 如果 null
不是要分配给属性的有效值,则它被视为必需属性。 映射到关系数据库架构时,必需属性创建为不可为 null 的列,可选属性创建为可为 null 的列。
- 属性
public class Blog { public int BlogId { get; set; } [Required] public string Url { get; set; } }
- Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(b => b.Url) .IsRequired(); }
七、列排序规则
可以定义文本列的排序规则,以确定如何比较和排序。
modelBuilder.Entity<Customer>().Property(c => c.Name) .UseCollation("SQL_Latin1_General_CP1_CI_AS");
如果数据库中的所有列都需要使用特定的排序规则,请改为在数据库级别定义排序规则。
八、列注释
可以对数据库列设置任意文本注释,从而在数据库中记录架构:
- 属性
public class Blog { public int BlogId { get; set; } [Comment("The URL of the blog")] public string Url { get; set; } }
- Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(b => b.Url) .HasComment("The URL of the blog"); }
九、列排序
默认情况下,在使用迁移建表时,EF Core 首先为主键列排序,然后为实体类型和从属类型的属性排序,最后为基类型中的属性排序。 但是,你可以指定不同的列顺序:
- 属性
public class EntityBase { [Column(Order = 0)] public int Id { get; set; } } public class PersonBase : EntityBase { [Column(Order = 1)] public string FirstName { get; set; } [Column(Order = 2)] public string LastName { get; set; } } public class Employee : PersonBase { public string Department { get; set; } public decimal AnnualSalary { get; set; } }
- Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Employee>(x => { x.Property(b => b.Id) .HasColumnOrder(0); x.Property(b => b.FirstName) .HasColumnOrder(1); x.Property(b => b.LastName) .HasColumnOrder(2); }); }