前言

本文来源于一位公众号童鞋私信我的问题,在我若加思索后给出了其中一种方案,在此之前我也思考过这个问题,借此机会我稍微看了下,目前能够想到的也只是本文所述方案。

为何要忽略主外键关系

我们不仅疑惑为何要忽略主外键关系呢?不难想到,相对于大型企业而言大部分都会采用不建立主外键关系(简称,外键约束),外键约束毫无疑问维护了数据一致性,但对其进行操作时很容易造成问题,级联删除只是其一。如果对于经常需要操作的表建立了外键约束,那么会严重影响插入、删除和更新的性能,因为在执行这些操作之前,数据库需要检查其是否违反数据完整性,这也就是为何大多数不管是DBA或者架构师完全放弃使用外键约束的原因,在分析数据库,它们并不能以事务方式(一次一行)来处理数据,而是批量处理,性能是一切,这是其二。随着业务需求变化在设计数据库时,可能需要存储历史数据库中的旧数据,而这些旧数据可能对数据质量和完整性没有严格要求。为了能够容纳旧的脏数据,可直接清理和转换旧数据,而放弃在数据库级别上强制执行参照完整性,这是其三。所以基于以上几点理由,忽略外键约束是有其原因所在,当然,是否放弃外键约束,可能取决于架构师或者DBA,反正决策权不在于搬砖的我们,我们知道其原因就好。

示例程序

以下示例皆在控制台中进行,老规矩,我们先给出示例模型,依然是Blog和Post两个实体,如下:

public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public List<Post> Posts { get; set; }
} public class Post
{
public int Id { get; set; }
public string Title { get; set; } public int BlogId { get; set; }
public Blog Blog { get; set; }
}

接下来则是定义上下文,如下:

public class EFCoreDbContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=.;Database=EFCore;Trusted_Connection=True;");
}
}

忽略外键约束

上述即使我们没有显式通过注解或Fluent APi配置关系,但是会根据约定而发现其关系,所以最终会建立外键约束,那么我们怎么才能在迁移时不建立外键约束呢?对依赖实体通过注解显式配置不映射,如下:

[NotMapped]
public List<Post> Posts { get; set; }

请注意,这里必须是对依赖实体进行显式注解不映射,若是对依赖实体上的主体导航属性配置依然会生成外键约束,若是对外键进行注解不映射也是同理,只不过生成的外键名称和默认的外键名称不一样而已。很显然,进行如上不建立外键约束后,当我们通过主体添加依赖体数据时将不会持久化到表中,比如如下通过Blog添加Posts

var context = new EFCoreDbContext();

context.Add(new Blog()
{
Name = "Jeffcky",
Posts = new List<Post>()
{
new Post()
{
Title = "EntityFramework Core"
}
}
}); var effectedRows = context.SaveChanges();

同理,当通过主体进行饥饿加载时将会抛出异常(无论是lambda表达式或字符串),比如如下,因为二者已经没有任何关联关系

var blog = context.Blogs.Include(d => d.Posts).FirstOrDefault(d => d.Id == );

基于上述,似乎没有什么很好的方式,只能采用最原始方式生成外键约束后,在迁移类中删除外键约束或数据库表手动删除外键约束,这样仍然可以很好的使用饥饿加载导航属性。一旦实体比较多,手动删除又显得比较麻烦,我们可以写个程序,当迁移完毕后删除数据库表所有外键,如下截取删除外键的代码片段,不知是否行得通,理论上应该是可以实现的。

public static class RemoveForeignKeyExetension
{
public static ModelBuilder RemoveForeignKeys(this ModelBuilder modelBuilder)
{
var entityTypes = modelBuilder.Model.GetEntityTypes().ToList(); for (int i = ; i < entityTypes.Count(); i++)
{
var entityType = entityTypes[i]; var references = entityType.GetDeclaredReferencingForeignKeys().ToList(); using (((Model)entityType.Model).Builder.Metadata.ConventionDispatcher.DelayConventions())
{
foreach (var reference in references)
{
reference.DeclaringEntityType.RemoveForeignKey(reference);
}
}
}
return modelBuilder;
}
}

忽略外键约束(SQLite)

上述是针对SQL Server所做的测试,理论上MySQL同理,但对于SQLite数据库,EF Core 3.x提供了全局方案:通过数据连接字符串配置【Foreign Keys = False】全局抑制建立外键约束。

optionsBuilder.UseSqlite("Database=sqlite.db;Foreign Keys=False");

总结

官方团队好像并未提供针对SQL Server或MySQL忽略而不建立外键约束而可以加载导航属性的办法,只能采取笨拙或者如上所述写个程序去删除外键约束或者通过注解方式实现,但是一旦使用注解将无法加载导航属性,那么用EF Core就失去了很大的意义,我认为

EntityFramework Core 迁移忽略主外键关系的更多相关文章

  1. 通过SQL脚本来查询SQLServer 中主外键关系

    在SQLServer中主外键是什么,以及主外键如何创建,在这里就不说了,不懂的可以点击这里,这篇文章也是博客园的博友写的,我觉得总结的很好: 此篇文章主要介绍通过SQL脚本来查看Sqlserver中主 ...

  2. MySQL创建数据表并建立主外键关系

    为mysql数据表建立主外键需要注意以下几点: 需要建立主外键关系的两个表的存储引擎必须是InnoDB. 外键列和参照列必须具有相似的数据类型,即可以隐式转换的数据类型. 外键列和参照列必须创建索引, ...

  3. SQL SERVER中获取表间主外键关系

    sql server 2008中的主外键关系获取方式: 转自:http://www.cnblogs.com/ke10/archive/2012/06/11/2544655.html SELECT OB ...

  4. SQL Server语句创建数据库和表——并设置主外键关系

    简单的创建数据库的 SQL 语句: use master go if exists(select * from sysdatabases where name='Test') begin select ...

  5. Sql Server有主外键关系时添加、删除数据

    当表之间有主外键关系时删除数据会被约束,添加.删除失败 解决办法,我们可以先把主外键关系的检查约束给关掉 → 然后删除数据 → 之后再把约束打开 查询出关掉所有外键约束的语句 SELECT 'ALTE ...

  6. Android Ormlite 学习笔记2 -- 主外键关系

    以上一篇为例子,进行主外键的查询 定义Users.java 和 Role.java Users -- Role 关系为:1对1 即父表关系 Role -- Users 关系为:1对多 即子表关系 下面 ...

  7. Entity Framework Code First主外键关系映射约定

    本篇随笔目录: 1.外键列名默认约定 2.一对多关系 3.一对一关系 4.多对多关系 5.一对多自反关系 6.多对多自反关系 在关系数据库中,不同表之间往往不是全部都单独存在,而是相互存在关联的.两个 ...

  8. SQL Server数据库中导入导出数据及结构时主外键关系的处理

    2015-01-26 软件开发中,经常涉及到不同数据库(包括不同产品的不同版本)之间的数据结构与数据的导入导出.处理过程中会遇到很多问题,尤为突出重要的一个问题就是主从表之间,从表有外检约束,从而导致 ...

  9. mysql中主外键关系

    一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为空,用来保证数据完整性 外键:是另一表的主键, ...

随机推荐

  1. Redis 入门到分布式 (七)Redis复制的原理与优化

    一.目录 Redis复制的原理与优化 什么是主从复制 全量复制和部分复制 复制的配置 故障处理 开发运维常见问题 二. 什么是主从复制 1.单机有什么问题? 单机如果机器故障,那么久无法及时提供服务: ...

  2. 核心记账业务可用jdk7的PriorityBlockingQueue优先阻塞队列结合乐观锁实现

    -- 1.优先级阻塞队列 当前核心记账业务是悲观锁实现,但考虑到高并发和死锁的问题,可以用PriorityBlockingQueue优先阻塞队列结合乐观锁实现,对于并发时出现锁无法update时可以重 ...

  3. Java实现 LeetCode 454 四数相加 II

    454. 四数相加 II 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0. 为 ...

  4. java实现最大镜像子串

    ** 最大镜像子串** [代码填空](满分12分) 串"abcba"以字母"c"为中心左右对称:串"abba" 是另一种模式的左右对称.这两 ...

  5. Linux 工作管理

    把进程放入后台 进程后加&,这时,进程在后台是运行的 tar -zcf etc.tar.gz /etc & 在执行程序时,快速按下ctrl+z快捷键,这时,进程在后台是停止的 查看后台 ...

  6. svg 贝塞尔曲线图解(记录)

    path路径绘制中,绘制贝塞尔曲线的命令包括: Q 二次贝赛尔曲线 x1,y1 x,y T 平滑二次贝塞尔曲线 x,y C 曲线(curveto) x1,y1 x2,y2 x,y S 平滑曲线 x2, ...

  7. 第一章04-Activity中常用的标志位

    Activity的LaunchMode Android中提供了四中Activity的启动模式 1. standard 2. singleTop 3. singleTask 4. signleInsta ...

  8. WDCP配置ThinkPHP5伪静态隐藏index.php,出现“”解决重定向次数过”问题

    站点域名的配置:xxx.com.conf server { listen 80; root /www/web/xxx_com/public_html; server_name xxx.com; ind ...

  9. react中使用decorator 封装context

    2020-03-27 react中使用decorator 封装context 在传统的react context中,子组件使用context十分繁琐,如果需要使用context的子组件多的话 每个组件 ...

  10. Ubuntu18.04下使用Hexo框架搭建个人博客

    一.安装node.js 说明:安装node.js的原因:Hexo框架是基于node.js. 1.推荐使用nvm安装速度快,也可自行百度其它方法. wget -qO- https://raw.githu ...