经过ToTable能够为数据模型在数据库中自定义表名,若是不配置,则表名为模型名的复数形式数据库
public class EmployeeConfig:IEntityTypeConfiguration<Employee> { public void Configure(EntityTypeBuilder<Employee> builder) { // 默认状况下,Employee实体在数据库中会生成Employees的数据表,这里经过ToTable(),将其指定为Employee builder.ToTable("Employee"); } }
在EF Core中,经过Fluent API作表间关系映射时,能够将API分为两类两种api
两类:has和withui
三种:One、Manycode
经过两类两种的组合,就能够完成绝大多数表间关系的映射,下面放一些经常使用的关系配置对象
public class EmployeeConfig:IEntityTypeConfiguration<Employee> { public void Configure(EntityTypeBuilder<Employee> builder) { builder.ToTable(nameof(Employee)); // 配置Employee表有一个Department对象,Department有多个Employee对象 // 这是典型的一对多配置 builder.HasOne(e => e.Department).WithMany(d=>d.Employees); } }
一般配置一对多的时候只须要在一张表上进行配置就能够了,但也能够在两张表上都进行配置,这样更清晰ci
public class DepartmentConfig:IEntityTypeConfiguration<Department> { public void Configure(EntityTypeBuilder<Department> builder) { builder.ToTable(nameof(Department)); // 配置Department表有多个Employee对象,Employee有一个Department对象 builder.HasMany(d => d.Employees).WithOne(e=>e.Department); // 配置Department表有一个领导(也是Employee对象),领导也属于一个部门 builder.HasOne(d => d.Leader).WithOne(e => e.Department); } }
在表关系的配置中,遵循 Has…( ).With…( )的配置方式,Has指的是配置的这张表,而后经过lambda表达式来指定对应的属性,如上面的Department表,经过lambda表达式 d => d.Employees 指定要配置的字段是Employess,HasMany则是指Department表的Employees对应多个文档
With则是前面has指定的属性对应的表,WithOne反过来指定了Employee表中的Department字段是一个字符串
因此这里就是一个多对一的配置get
经过这四个单词的组合,就能够完成一对多、一对1、多对多(经过中间表拆分红两个一对多)的表间关系配置string
这里将Entity文件放出来,以便更好理解
public class Employee { public Guid Id { get; set; } public string Name { get; set; } public bool Gender { get; set; } public string Phone { get; set; } public decimal Rating { get; set; } public decimal Salary { get; set; } public Guid DepartmentId { get; set; } public Department Department { get; set; } } public class Department { public Guid Id { get; set; } public string Name { get; set; } public Guid LeaderId { get; set; } public Employee Leader { get; set; } public List<Employee> Employees { get; set; } public string NoUse { get; set; } }
EF Core会自动将实体中名为Id的属性设置为主键,可是有时候主键并非这么规整的命名,或者须要联合主键的状况,就须要手动指定主键
public class DepartmentConfig:IEntityTypeConfiguration<Department> { public void Configure(EntityTypeBuilder<Department> builder) { // 配置数据库中主键为实体的Id字段 builder.HasKey(d => d.Id); } }
这里指定了Department的Id字段为主键,实体属性名为Id不用手动指定,这里只是展现一下自定义的语法
public class DepartmentConfig:IEntityTypeConfiguration<Department> { public void Configure(EntityTypeBuilder<Department> builder) { // 配置数据库中主键为实体的Id和Name的联合主键 builder.HasKey(d => new {d.Id, d.Name}); } }
联合主键的设置也很简单,经过new一个匿名对象的方式提供
EF Core会默认为主键生成值,但有时候咱们但愿使用主键而且本身自定义相关的值,好比说自选帐号、课程Id等,这时能够这样配置
public class DepartmentConfig:IEntityTypeConfiguration<Department> { public void Configure(EntityTypeBuilder<Department> builder) { builder.Property(d => d.Id) .ValueGeneratedNever(); // 配置数据库中实体的Id字段不自动生成值 } }
经过ValueGeneratedNever()能够禁用自动生成值,实际上它能够给任何一个属性都配置,可是一般只有主键是默认生成值的
若是有外键则必须有另外一个与之关联的表,因此外键配置只能在表关系配置后附加
EF Core会默认将关联表+Id的字段设置为外键,同主键同样,有时候不是那么规整,就须要手动指定
public class DepartmentConfig:IEntityTypeConfiguration<Department> { public void Configure(EntityTypeBuilder<Department> builder) { builder.HasOne(d => d.Leader).WithOne(e => e.Department).HasForeignKey("LeaderId"); } }
在Department实体中指定了Leader,Leader也是Employee对象,若是依照约定属性为EmployeeId会自定设置为外键字段,可是这里指定了LeaderId,就须要手动设置外键字段为LeaderId
public class DepartmentConfig:IEntityTypeConfiguration<Department> { public void Configure(EntityTypeBuilder<Department> builder) { // 数据库中忽略该字段,该字段不会存在该实体属性对应的字段 builder.Ignore(d => d.NoUse); } }
前面Department实体中有一个NoUse字段,可是不但愿它在数据库中映射该字段,就能够经过Ignore的方式忽略掉
经过Fluent API可以对字段进行约束,这样在生成数据库表时就会将相应的约束生成,如设置了字段的最大长度在数据库表中的字段数据类型时nvarchar(设定的最大长度),若是没有设置,在数据库表中的字段数据类型则是nvarchar(max)
Fluent支持流式语法,能够将多个约定流式附加
public class DepartmentConfig:IEntityTypeConfiguration<Department> { public void Configure(EntityTypeBuilder<Department> builder) { // 设置姓名字段不为空 builder.Property(d => d.Name).IsRequired(); } }
public class DepartmentConfig:IEntityTypeConfiguration<Department> { public void Configure(EntityTypeBuilder<Department> builder) { // 设置姓名字段最大长度为30,且不为空 builder.Property(d => d.Name).HasMaxLength(30).IsRequired(); } }
public class EmployeeConfig:IEntityTypeConfiguration<Employee> { public void Configure(EntityTypeBuilder<Employee> builder) { // Phone字段在数据库中为11位固定长度字符串 IsFixedLength()用于指定该字段是否为固定长度 builder.Property(e => e.Phone).HasMaxLength(11).IsFixedLength(); } }
IsFixedLength()用于指定该字段是否为固定长度,其长度为前面设置的字段最大长度
public class EmployeeConfig:IEntityTypeConfiguration<Employee> { public void Configure(EntityTypeBuilder<Employee> builder) { // 显式指定实体属性对应数据库中的字段名,这里指定Phone字段对应的数据库字段为ChinaPhone builder.Property(e => e.Phone).HasColumnName("ChinaPhone"); } }
public class EmployeeConfig:IEntityTypeConfiguration<Employee> { public void Configure(EntityTypeBuilder<Employee> builder) { // 指定decimal的精度为5刻度为2 builder.Property(e => e.Rating).HasColumnType("decimal(5, 2)"); } }
注:关于精度和刻度的解释,精度是数字的位数,刻度是小数的位数,即decimal(5, 2)能表示的最大数是999.99,一共五位,小数两位
指定数据类型更经常使用的状况是将实体的decimal类型指定为数据库中的money类型
public class EmployeeConfig:IEntityTypeConfiguration<Employee> { public void Configure(EntityTypeBuilder<Employee> builder) { // 指定decimal的精度为5刻度为2 builder.Property(e => e.Salary).HasColumnType("money"); } }
由于进行了分组配置,将每一个类的配置分别拆分到不一样的文件
具体的配置能够看看微软的官方文档