Entity Framework——建模建库

1数据库初始化策略选择

三种初始化策略:

1)CreateDatabaseIfNotExists:默认的策略。如果数据库不存在,那么就创建数据库。但是如果数据库已存在,而且实体发生了变化,就会出现异常。

2)DropCreateDatabaseIfModelChanges:模型改变时,原来的数据库会被删除,自动重新创建一个新的数据库。

3)DropCreateDatabaseAlways:每次运行都会删除原来的数据库,然后重新生成数据库。

4)Null:在Codefirst模式下,当实体结构改变时,运行程序不会自动生成表,改变实体结构与改变表结构互不影响,

前三种策略无法应对的问题是:分别改变实体模型和数据库表结构。即,当使用CreateDatabaseIfNotExists策略时,修改实体模型会抛异常(The model backing the <Database> context has changed since the database was created

);若使用DropCreateDatabaseIfModelChanges模式,那么每次运行都会重新生成数据库,这导致历史数据丢失,然而提前备份数据这种策略比较麻烦,尤其是系统上线以后。

解决办法:

采用第四种初始化策略,初次使用codefirst方式创建好数据库以后,不使用任何数据库初始化策略,即给Database.SetInitializer传null。

[DbConfigurationType(typeof(MySqlEFConfiguration))]
public class HY_WebApiContext : DbContext
{
  public HY_WebApiContext(): base("name=HY_WebApiContext")
  {
    Database.SetInitializer<HY_WebApiContext>(null);
  }
  ......
}

2实体关系与依赖默认规则创建的表关系

Codefirst模式下,实体与表之间的映射,随实体关系的不同而不同。

1)实体之间为一对一关系

实体

     public class EntityOne
        {
            public int Id { get; set; }
            public string FieldEntityOne { get; set; }
            public EntityTwo EntityTwo { get; set; }
        }

        public class EntityTwo
        {
            public int Id { get; set; }
            public string FieldEntityTwo { get; set; }
        }

表结构

entityones,其中EntityTwo_Id为外键。

EntityTwo

2)实体间的一对多关系

实体

     public class EntityOne
        {
            public int Id { get; set; }
            public string FieldEntityOne { get; set; }
            public List<EntityTwo> EntityTwos { get; set; }
        }

        public class EntityTwo
        {
            public int Id { get; set; }
            public string FieldEntityTwo { get; set; }
        }

表结构

entityones

entitytwoes,其中EntityOne_Id是外键

3)实体间的多对多关系

实体

     public class EntityOne
        {
            public int Id { get; set; }
            public string FieldEntityOne { get; set; }
            public List<EntityTwo> EntityTwos { get; set; }

        }

        public class EntityTwo
        {
            public int Id { get; set; }
            public string FieldEntityTwo { get; set; }
        public List<EntityOne> EntityOnes { get; set; }
        }

表结构

Codefirst模式下,两个实体间的多对多关系,映射为三张表,其中一张表表示实体间的联系。

entityones

entitytwoes

entitytwoentityones,其中EntityTwo_Id和EntityOne_Id是外键,这两个外键构成了改表的复合主键。

4)实体包含类型相同的两个或多个名称不同的导航属性

实体

public class EntityOne
{
     public int Id { get; set; }
     public string FieldEntityOne { get; set; }
     public EntityTwo EntityTwos { get; set; }
     public EntityTwo EntityTwosOther { get; set; }
}

 public class EntityTwo
 {
     public int Id { get; set; }
     public string FieldEntityTwo { get; set; }
 }

Entityones,其中EntityTwos_Id、EntityTwosOther_Id是外键。

entitytwoes

3为关系创建实体:

一个用户可以订阅多种出版物,一种出版物可被多个用户订阅,实体建模如下:

public class Publication
{
  public int Id { get; set; }
  public virtual ICollection<User> Users { get; set; }
  ......
}

public class User
{
  public int Id { get; set; }
  public virtual ICollection<Publication> Publications { get; set; }
  ......
}

EF框架对上述多对多关系的默认处理方式为生成三张表:publications,user,publicationusers

其中publicationusers为关系表,表的属性只包括两个表的主键。

问题1:publications表的数据会大量重复:假设用户A订阅了电子学报,publications表里会有一条关于电子学报的记录,当用户B也订阅电子学报的时候,又会将这条数据插入publications表,如此等等。

解决方案

每次向publications表插入记录时,先在表中查找待插入的刊物是否存在,如果存在就不插入,只更新publicationusers表。

问题2:虽然使用上面的方法可以解决这个问题,但用户何时订阅了一种刊物,这类信息没有被记录下来。

解决方案:

添加一个实体,表达publications,user这两个实体之间的关系,实体如下:

public class Publication
{
  public int Id { get; set; }
  ......
}
public class User
{
  public int Id { get; set; }
  ......
}

public class PublicationUser
{
        public int Id { get; set; }
        /// <summary>
        /// 出版物
        /// </summary>
        public Publication Publication { get; set; }
        /// <summary>
        /// 所属用户
        /// </summary>
        public User User { get; set; }
        /// <summary>
        /// 记录插入时间
        /// </summary>
        public DateTime InsertTime { get; set; }
        /// <summary>
        /// 记录修改时间
        /// </summary>
        public DateTime UpdateTime { get; set; }
}

经上述处理后,EF仍然生成三张表publications,user,publicationusers,与之前不同的是publicationusers表中多了Id ,InsertTime ,UpdateTime 这三个字段,同时去掉了publications,user其中的导航属性,这样的设计满足需求,且无冗余。那么经过这样的修改后,每一个PublicationUser实例对应了表中的一条记录。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏xingoo, 一个梦想做发明家的程序员

大数据之Yarn——Capacity调度器概念以及配置

试想一下,你现在所在的公司有一个hadoop的集群。但是A项目组经常做一些定时的BI报表,B项目组则经常使用一些软件做一些临时需求。那么他们肯定会遇到同时提交...

2089
来自专栏容器云生态

红帽子RHCS套件安装与配置(一)

RHCS提供的三个核心功能  高可用集群是RHCS的核心功能。当应用程序出现故障,或者系统硬件、网络出现故障时,应用可以通过RHCS提供的高可用性服务管理组件...

2425
来自专栏aoho求索

基于redis的分布式锁实现

关于分布式锁 很久之前有讲过并发编程中的锁并发编程的锁机制:synchronized和lock。在单进程的系统中,当存在多个线程可以同时改变某个变量时,就需要...

3468
来自专栏积累沉淀

Java设计模式(八)----代理模式

代理描述 1.生活中: 代理就是一个人或者一个组织代表其他人去做一件事的现实生活中的。在一些情况下,一个客户不想或者不能够直接引用一个对...

1789
来自专栏linux驱动个人学习

Linux下0号进程的前世(init_task进程)今生(idle进程)----Linux进程的管理与调度(五)【转】

Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2)

512
来自专栏北京马哥教育

Linux性能及调优指南:进程管理

Linux进程管理 进程管理是操作系统的最重要的功能之一。有效率的进程管理能保证一个程序平稳而高效地运行。 Linux的进程管理与UNIX的进程管理相似。它...

3296
来自专栏后端技术探索

Nginx服务器架构简析

模块化结构的思想是一个很久的概念,但也正是成熟的思想造就了Nginx的巨大优越性。

453
来自专栏java工会

美团云计算方面面试题

842
来自专栏运维技术迷

Redis单线程架构

redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库服务。 引出单线程模型 开启三个redis-cli客户端同时执行命令 客户端1设置一个字...

3078
来自专栏北京马哥教育

MySQL架构

1.MySQL整体逻辑架构 我们先下图看看MySQL整体逻辑架构(MySQL’s Logical Architecture) ? ...

3108

扫描关注云+社区