当前位置: 移动技术网 > IT编程>开发语言>.net > Entity Framework 查漏补缺 (三)

Entity Framework 查漏补缺 (三)

2019年01月28日  | 移动技术网IT编程  | 我要评论

开复学生网,圣徒下载,剑心仙缘

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

数据库生成一张表

 

  • 另一种方式(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:

    

historybooks:

映射方式一:data annotation

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

 如:

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项目的代码 

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网