数据库文档-陈海云妇科讲座文档库
本文内容
模型中的每个实体类型都有一组属性,EF Core 将从数据库中读取和写入这些属性。 如果您使用的是关系数据库,则实体属性会映射到表列。
包含和排除的属性
按照规定,所有具有 getter 和 setter 的公共属性都将包含在模型中。
具体属性可以排除如下:
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[NotMapped]
public DateTime LoadedFromDatabase { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity()
.Ignore(b => b.LoadedFromDatabase);
}
列名
按照惯例,在使用关系数据库时,实体属性会映射到与该属性同名的表列。
如果您希望配置具有不同名称的列,您可以使用以下代码片段来实现:
public class Blog
{
[Column("blog_id")]
public int BlogId { get; set; }
public string Url { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity()
.Property(b => b.BlogId)
.HasColumnName("blog_id");
}
列数据类型
使用关系数据库时,数据库提供者根据属性的 .NET 类型选择数据类型。 它还会考虑其他元数据,例如已配置、属性是否是主键的一部分等。
例如数据库文档,SQL Server 将 DateTime 属性映射到 datetime2(7) 列,将字符串属性映射到 nvarchar(max) 列(或 nvarchar(450) 用于用作键的属性)。
列也可以配置为指定列的确切数据类型。 例如,以下代码将 Url 配置为最大长度为 200 的非 unicode 字符串,并将 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; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity(
eb =>
{
eb.Property(b => b.Url).HasColumnType("varchar(200)");
eb.Property(b => b.Rating).HasColumnType("decimal(5, 2)");
});
}
最大长度
配置最大长度向数据库提供者提供有关为给定属性选择合适的列数据类型的提示。 最大长度仅适用于数组数据类型,例如 string 和 byte[]。
注意
在将数据传递给提供者之前,实体框架不执行任何最大长度验证。 相反,由提供者或数据存储来适当地验证。 例如,当面向SQL Server 时,超过最大长度将导致异常,因为基础列的数据类型不允许存储多余的数据。
在以下示例中,将最大长度配置为 500 会导致在 SQL Server 上创建类型为 nvarchar(500) 的列:
public class Blog
{
public int BlogId { get; set; }
[MaxLength(500)]
public string Url { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity()
.Property(b => b.Url)
.HasMaxLength(500);
}
精度和规模
某些关系数据类型支持精度和比例方面,用于控制可以存储哪些值,以及一列需要多少存储空间。 哪些数据类型支持精度和小数位数取决于数据库,但在大多数数据库中,decimal 和 DateTime 类型支持这些方面。 对于 decimal 属性,precision 定义了表示列将包含的任何值所需的最大位数,scale 定义了所需的最大小数位数。 对于 DateTime 属性,精度定义表示秒的一小部分所需的最大位数,不使用小数位。
注意
在将数据传递给提供者之前,实体框架不执行任何精度或比例验证。 相反,由提供者或数据存储来适当地验证。 例如,当以 SQL Server 为目标时,数据类型 datetime 的列不允许精度,而 datetime2 的精度可以在 0 到 7 之间(含)。
在以下示例中,将 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; }
}
没有先定义精度就永远不会定义比例,所以定义比例的数据注释是[Precision(precision, scale)]。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity()
.Property(b => b.Score)
.HasPrecision(14, 2);
modelBuilder.Entity()
.Property(b => b.LastUpdated)
.HasPrecision(3);
}
如果不先定义精度,就永远不会定义比例,因此用于定义比例的 Fluent API 是 HasPrecision(precision, scale)。
统一码
在一些关系数据库中,存在不同的类型来表示 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; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity()
.Property(b => b.Isbn)
.IsUnicode(false);
}
必需和可选属性
如果属性包含 null 是有效的数据库文档,则该属性被认为是可选的。 如果 null 不是分配给属性的有效值,则它被视为必需属性。 映射到关系数据库模式时,必需属性创建为不可空列,可选属性创建为可空列。
协议
按照约定,.NET类型可以包含null的属性配置为optional,.NET类型不能包含null的属性配置为required。 例如,根据需要将所有具有 .NET 值类型(int、decimal、bool 等)的属性配置为可选,并将所有具有可为 null 的 .NET 值类型(int?、decimal?、bool? 等)的属性配置为可选。
C# 8 引入了一个称为可空引用类型 (NRT) 的新功能,它允许对引用类型进行注释以指示它们是否可以包含空值。 此功能在新项目模板中默认启用,但在现有项目中保持禁用状态,除非明确选择加入。可空引用类型通过以下方式影响 EF Core 的行为:
以下示例演示了具有必需属性和可选属性以及禁用和启用可为空引用的实体类型:
public class CustomerWithoutNullableReferenceTypes
{
public int Id { get; set; }
[Required] // Data annotations needed to configure as required
public string FirstName { get; set; }
[Required]
public string LastName { get; set; } // Data annotations needed to configure as required
public string MiddleName { get; set; } // Optional by convention
}
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; } // Required by convention
public string LastName { get; set; } // Required by convention
public string? MiddleName { get; set; } // Optional by convention
// Note the following use of constructor binding, which avoids compiled warnings
// for uninitialized non-nullable properties.
public Customer(string firstName, string lastName, string? middleName = null)
{
FirstName = firstName;
LastName = lastName;
MiddleName = middleName;
}
}
建议使用可空引用类型,因为它将 C# 代码中表达的可空性传递给 EF Core 的模型和数据库,并避免使用流畅的 API 或数据注释表达相同的概念两次。
注意
在现有项目上启用可空引用类型时应注意:以前配置为可选属性的引用类型属性现在将根据需要进行配置,除非它们被显式注释为可空。 在管理关系数据库模式时,这可能会导致生成迁移,从而改变数据库列的可空性。
若要详细了解可空引用类型以及如何将它们与 EF Core 一起使用,请参阅此功能的专用文档页面。
显式配置
按照惯例可选的属性可以按需要配置如下:
public class Blog
{
public int BlogId { get; set; }
[Required]
public string Url { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity()
.Property(b => b.Url)
.IsRequired();
}
列整理
可以定义文本列的排序规则以确定它们的比较和排序方式。 例如,以下代码片段将 SQL Server 列配置为不区分大小写:
modelBuilder.Entity().Property(c => c.Name)
.UseCollation("SQL_Latin1_General_CP1_CI_AS");
如果数据库中的所有列都需要使用特定的排序规则,请改为在数据库级别定义排序规则。
有关 EF Core 对排序规则的支持的一般信息,请参阅排序规则文档页面。
专栏评论
可以在数据库列上设置任意文本注释,从而记录数据库中的模式:
public class Blog
{
public int BlogId { get; set; }
[Comment("The URL of the blog")]
public string Url { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity()
.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(x =>
{
x.Property(b => b.Id)
.HasColumnOrder(0);
x.Property(b => b.FirstName)
.HasColumnOrder(1);
x.Property(b => b.LastName)
.HasColumnOrder(2);
});
}
请注意,一般情况下,大多数数据库只支持在创建表时对列进行排序。 这意味着无法使用列顺序功能对现有表中的列进行重新排序。