EntityFramework Core 迁移忽略主外键关系
前言
本文来源于一位公众号童鞋私信我的问题,在我若加思索后给出了其中一种方案,在此之前我也思考过这个问题,借此机会我稍微看了下,目前能够想到的也只是本文所述方案。
为何要忽略主外键关系
我们不仅疑惑为何要忽略主外键关系呢?不难想到,相对于大型企业而言大部分都会采用不建立主外键关系(简称,外键约束),外键约束毫无疑问维护了数据一致性,但对其进行操作时很容易造成问题,级联删除只是其一。如果对于经常需要操作的表建立了外键约束,那么会严重影响插入、删除和更新的性能,因为在执行这些操作之前,数据库需要检查其是否违反数据完整性,这也就是为何大多数不管是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 迁移忽略主外键关系的更多相关文章
- 通过SQL脚本来查询SQLServer 中主外键关系
在SQLServer中主外键是什么,以及主外键如何创建,在这里就不说了,不懂的可以点击这里,这篇文章也是博客园的博友写的,我觉得总结的很好: 此篇文章主要介绍通过SQL脚本来查看Sqlserver中主 ...
- MySQL创建数据表并建立主外键关系
为mysql数据表建立主外键需要注意以下几点: 需要建立主外键关系的两个表的存储引擎必须是InnoDB. 外键列和参照列必须具有相似的数据类型,即可以隐式转换的数据类型. 外键列和参照列必须创建索引, ...
- SQL SERVER中获取表间主外键关系
sql server 2008中的主外键关系获取方式: 转自:http://www.cnblogs.com/ke10/archive/2012/06/11/2544655.html SELECT OB ...
- SQL Server语句创建数据库和表——并设置主外键关系
简单的创建数据库的 SQL 语句: use master go if exists(select * from sysdatabases where name='Test') begin select ...
- Sql Server有主外键关系时添加、删除数据
当表之间有主外键关系时删除数据会被约束,添加.删除失败 解决办法,我们可以先把主外键关系的检查约束给关掉 → 然后删除数据 → 之后再把约束打开 查询出关掉所有外键约束的语句 SELECT 'ALTE ...
- Android Ormlite 学习笔记2 -- 主外键关系
以上一篇为例子,进行主外键的查询 定义Users.java 和 Role.java Users -- Role 关系为:1对1 即父表关系 Role -- Users 关系为:1对多 即子表关系 下面 ...
- Entity Framework Code First主外键关系映射约定
本篇随笔目录: 1.外键列名默认约定 2.一对多关系 3.一对一关系 4.多对多关系 5.一对多自反关系 6.多对多自反关系 在关系数据库中,不同表之间往往不是全部都单独存在,而是相互存在关联的.两个 ...
- SQL Server数据库中导入导出数据及结构时主外键关系的处理
2015-01-26 软件开发中,经常涉及到不同数据库(包括不同产品的不同版本)之间的数据结构与数据的导入导出.处理过程中会遇到很多问题,尤为突出重要的一个问题就是主从表之间,从表有外检约束,从而导致 ...
- mysql中主外键关系
一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为空,用来保证数据完整性 外键:是另一表的主键, ...
随机推荐
- (三)用less+gulp+requireJs 搭建项目(requireJs)
首先我想说下我在写js时经常遇到的问题,尤其是很大的项目: 1.我一般会把各个功能分块写在各个js文件中: 比如弹出框: dialog.js $(document).ready(function(){ ...
- Java实现 LeetCode 283 移动零
283. 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必 ...
- ubuntu下Vivado launch SDK后,SDK无菜单栏解决办法
最近在调Xilinx的ZYNQ 7015,按照教程从Vivado中Launch SDK后遇到了个问题,SDK的菜单栏消失了,真的没了,我的环境是ubuntu 16.4.百度好久都没有人遇到该问题,经过 ...
- [leetcode] 股票问题
参考文章: [1] 团灭 LeetCode 股票买卖问题 [2] Most consistent ways of dealing with the series of stock problems 其 ...
- 3.keras-简单实现Mnist数据集分类
keras-简单实现Mnist数据集分类 1.载入数据以及预处理 import numpy as np from keras.datasets import mnist from keras.util ...
- [原创][开源] SunnyUI.Net 更新日志
SunnyUI.Net, 基于 C# .Net WinForm 开源控件库.工具类库.扩展类库.多页面开发框架 Blog: https://www.cnblogs.com/yhuse Gitee: h ...
- Python 3中,import win32com.client 出错
在 import win32com.client 时,出现了界面: Traceback (most recent call last): File "<pyshell#1>&qu ...
- @bzoj - 4035@ [HAOI2015]数组游戏
目录 @description@ @solution@ @accepted code@ @details@ @description@ 有一个长度为N的数组,甲乙两人在上面进行这样一个游戏: 首先,数 ...
- JavaScript触发器
感谢:链接(视频讲解很详细) JavaScript触发器 一.功能 顾名思义就是操控鼠标或键盘触发(实现)一些特定功能. 二.功能实现 <script type="text/javas ...
- css方法1(清除ul边距间隙,两端对齐,字母大写,首字放大)
一.清除ul自带左边间距 ul{ margin:; padding:; } 二.ul li 与li 之间隙 1.ul 设置font-size:0 ; 子li 设置字体大小 2.把li写到一起,不换行 ...