欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

EF Core中通过Fluent API完成对表的配置

程序员文章站 2022-05-03 10:35:21
EF Core中通过Fluent API完成对表的配置 设置实体在数据库中的表名 通过ToTable可以为数据模型在数据库中自定义表名,如果不配置,则表名为模型名的复数形式 public class EmployeeConfig:IEntityTypeConfiguration ......

ef core中通过fluent api完成对表的配置

设置实体在数据库中的表名

通过totable可以为数据模型在数据库中自定义表名,如果不配置,则表名为模型名的复数形式

public class employeeconfig:ientitytypeconfiguration<employee>
{
    public void configure(entitytypebuilder<employee> builder)
    {
        // 默认情况下,employee实体在数据库中会生成employees的数据表,这里通过totable(),将其指定为employee
        builder.totable("employee");
    }
}

表间关系映射

在ef core中,通过fluent api做表间关系映射时,可以将api分为两类两种

两类:has和with

三种:one、many

通过两类两种的组合,就可以完成绝大多数表间关系的映射,下面放一些常用的关系配置

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);
    }
}

通常配置一对多的时候只需要在一张表上进行配置就可以了,但也可以在两张表上都进行配置,这样更清晰

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字段是一个

所以这里就是一个多对一的配置

通过这四个单词的组合,就可以完成一对多、一对一、多对多(通过中间表拆分成两个一对多)的表间关系配置

这里将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)
    {
        // 设置salary在数据库中的类型为money(sql server的一个数据类型,不晓得其他数据库支持不)
        builder.property(e => e.salary).hascolumntype("money");
    }
}

为什么我的fluent api配置长这样

因为进行了分组配置,将每个类的配置分别拆分到不同的文件

具体的配置可以看看微软的官方文档