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

Entity Framework 查漏补缺 (三)

程序员文章站 2022-03-10 16:01:37
Code First的数据库映射 有两种方式来实现数据库映射: 数据属性:Data Annotation 映射配置: Fluent API 有继承关系的实体如何映射? Code First在生成数据库表时,默认使用TPH方式 就是把父类和子类生成同一张表,额外增加了一列Discriminator字段 ......

code first的数据库映射

有两种方式来实现数据库映射:

  • 数据属性:data annotation
  • 映射配置: fluent api

有继承关系的实体如何映射?

  • code first在生成数据库表时,默认使用tph方式

就是把父类和子类生成同一张表,额外增加了一列discriminator字段,区分是父类或子类的数据类型

比如:

父类book对象

public class book
{
    [key]
    [databasegenerated(databasegeneratedoption.identity)]
    public int bookid { get; set; }
    public string bookname { get; set; }
    public int pages { get; set; }
}

子类historybooks对象,继承book

public class historybooks:book
{
    public int chapter { get; set; }
}

数据库生成一张表

Entity Framework 查漏补缺 (三)

 

  • 另一种方式(data annotation实现):tpt

不管父类子类,各自生成一张表,以及在子类中增加两者联系的外键;

定义tpt方式 父类和子类定义 [table("xxx")]

如:

父类

[table("book")]
public class book
{
    [key]
    [databasegenerated(databasegeneratedoption.identity)]
    public int bookid { get; set; }
    public string bookname { get; set; }
    public int pages { get; set; }
}

子类

[table("historybooks")]
public class historybooks:book
{public int chapter { get; set; }
}

映射数据生成的两张表

book:

Entity Framework 查漏补缺 (三)    

historybooks:

Entity Framework 查漏补缺 (三)

映射方式一:data annotation

给实体对象的属性加上注解特性,实现与数据库之间建立映射关系并进行控制

 如:

Entity Framework 查漏补缺 (三)

booid映射到表中字段为自增的主键

dataannotations 包含的常用特性:

keyattribute:对应数据库中表的主键的设置

requiredattribute:对应数据库中字段的数据不可null

maxlengthattribute:对应数据库中字符串类型字段的最大长度

concurrencycheckattribute:指定用于开放式并发检查的列的数据类型

timestampattribute:将列的数据类型指定为行版本

databasegeneratedattribute:标记指定实体属性是由数据库生成的,并指定生成策略(none数据库不生成值,identity当插入行时,数据库生成值,computed当插入或更新行时,数据库生成值)

tableattribute:指定实体类对应的数据表名

columnattribute:指定实体属性在数据库中的列名

foreignkeyattribute :指定导航属性的外键字段

notmappeattribute:不映射对应字段

映射方式二:fluent api

fluent api的配置方式可以将实体类与映射配置进行解耦合

有两种方式来实现fluent api的映射配置

  • 第一种:重写dbcontext的中onmodelcreating方法

如下面的book类,不再有data annotation特性

public class book
{
    public int bookid { get; set; }
    public string bookname { get; set; }
    public int pages { get; set; }
}

重写dbcontext中的onmodelcreating方法实现book类映射的配置:

protected override void onmodelcreating(dbmodelbuilder modelbuilder)
{
    modelbuilder.entity<book>().haskey(t => t.bookid);

    base.onmodelcreating(modelbuilder);
}

现实项目中,实体对象可能是非常多的,在onmodelcreating方法中逐一进行映射配置,可想而知会造成dbcontext的代码庞大。

  • 第二种:新建bookmap类,并继承entitytypeconfiguration<entitytype>

1、在新建的bookmap类实现映射配置

public class bookmap : entitytypeconfiguration<book>
{
    public bookmap()
    {
        this.totable("book", "dbo");
        this.haskey(p => p.bookid);
        //this.haskey(p => new { p.bookid, p.bookpreid });//关联主键  
        this.property(p => p.bookid).hasdatabasegeneratedoption(databasegeneratedoption.identity);//自动生成
        this.property(p => p.bookname).isrequired().hasmaxlength(20).hascolumnname("bookname").isunicode(false);//非空,最大长度20,自定义列名,列类型为varchar而非nvarchar
        this.ignore(p => p.bookdescription);//忽略改属性的映射
    }
}

2、依旧重写dbcontext中的onmodelcreating方法,将bookmap 类的实例添加到modelbuilder的configurations。

protected override void onmodelcreating(dbmodelbuilder modelbuilder)
{
    modelbuilder.configurations.add(new bookmap());
}

这样能大大减少onmodelcreating的代码量,依然存在一个问题,就是实体对象一多,还是要逐条将map类的实例添加到modelbuilder的configurations

3、利用反射将程序集中所有的entitytypeconfiguration添加到modelbuilder.configurations中,可以说完全解耦了

protected override void onmodelcreating(dbmodelbuilder modelbuilder)
{
    var typestoregister = assembly.getexecutingassembly().gettypes()
                        .where(type => !string.isnullorempty(type.namespace))
                        .where(type => type.basetype != null && type.basetype.isgenerictype && type.basetype.getgenerictypedefinition() == typeof(entitytypeconfiguration<>));
    foreach (var type in typestoregister)
    {
        dynamic configurationinstance = activator.createinstance(type);
        modelbuilder.configurations.add(configurationinstance);
    }
}

注:此段代码源自网友文章,摘自nopcommerce项目的代码