EF Core 中处理 1对1 关系
最近在开发记录感想功能的时候用到了1对1的数据关系,具体情况是这样的,有这样两个1对1的类型
public class Item
{
public int Id { get; set; }
public string Title { get; set; }
public Note Note { get; set; }
}
public class Note
{
public int Id { get; set; }
public string Content { get; set; }
public int ItemId { get; set; }
public Item Item { get; set; }
public bool Deleted { get; set; }
}
它们的1对1关系配置如下:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Note>(e =>
{
e.HasOne(x => x.Item).WithOne(x => x.Note).HasForeignKey<Note>(x => x.ItemId);
e.HasQueryFilter(x => !x.Deleted);
});
}
Note是软删除的,这里配置了一个QueryFilter
然后我们用dotnet-ef命令构建数据库,生成的脚本如下:
IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL
BEGIN
CREATE TABLE [__EFMigrationsHistory] (
[MigrationId] nvarchar(150) NOT NULL,
[ProductVersion] nvarchar(32) NOT NULL,
CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId])
);
END;
GO
CREATE TABLE [Items] (
[Id] int NOT NULL IDENTITY,
[Title] nvarchar(max) NULL,
CONSTRAINT [PK_Items] PRIMARY KEY ([Id])
);
GO
CREATE TABLE [Notes] (
[Id] int NOT NULL IDENTITY,
[Content] nvarchar(max) NULL,
[ItemId] int NOT NULL,
[Deleted] bit NOT NULL,
CONSTRAINT [PK_Notes] PRIMARY KEY ([Id]),
CONSTRAINT [FK_Notes_Items_ItemId] FOREIGN KEY ([ItemId]) REFERENCES [Items] ([Id]) ON DELETE CASCADE
);
GO
CREATE UNIQUE INDEX [IX_Notes_ItemId] ON [Notes] ([ItemId]);
GO
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20190813141425_InitEntities', N'2.2.6-servicing-10079');
GO
再造一条数据,方便测试
USE [demo]
GO
INSERT INTO [dbo].[Items]
([Title])
VALUES
('a')
GO
不出意外的话,这个Item的Id会是1
业务代码如下:
[ApiController]
[Route("[controller]")]
public class NoteController : ControllerBase
{
private readonly DemoContext _db;
public NoteController(DemoContext db)
{
_db = db;
}
[HttpGet]
public IEnumerable<Note> Get()
{
return _db.Notes.ToList();
}
[HttpPost]
public void Post()
{
var item = _db.Items.Include(x => x.Note).FirstOrDefault(x => x.Id == 1);
if (item != null)
{
item.AddNote(DateTime.Now.ToString("F"));
_db.SaveChanges();
}
}
[HttpDelete]
public void Delete()
{
var item = _db.Items.Include(x => x.Note).FirstOrDefault(x => x.Id == 1);
if (item != null)
{
item.DeleteNote();
_db.SaveChanges();
}
}
}
就是对Id==1的Item新增/修改/删除Note
有这样一个很简单的场景,用户先新增了Note,然后删除Note,再想新增Note,这时候你就会发现数据库报错了:Note违反了唯一性约束。
由于Note是软删除的,所有当再次新增Note的时候就会出现重复的ItemId。
解决这个问题的思路也很简单,只需要把这个外键的唯一性约束更改为过滤掉Deleted的数据进行约束。
更改关系配置
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Note>(e =>
{
e.HasOne(x => x.Item).WithOne(x => x.Note).HasForeignKey<Note>(x =x.ItemId);
e.HasQueryFilter(x => !x.Deleted);
e.HasIndex(x => x.ItemId).IsUnique().HasFilter($"[{nameof(Note.Deleted)}]=0");
});
}
给这个ItemId的唯一性约束加一个条件e.HasIndex(x => x.ItemId).IsUnique().HasFilter($"[{nameof(Note.Deleted)}]=0");
再用dotnet-ef命令生成的数据库更新脚本,如下:
DROP INDEX [IX_Notes_ItemId] ON [Notes];
GO
CREATE UNIQUE INDEX [IX_Notes_ItemId] ON [Notes] ([ItemId]) WHERE [Deleted]=0;
GO
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20190813144240_FilterIndex', N'2.2.6-servicing-10079');
GO
用有条件的INDEX替换了原先的INDEX
现在再次执行先前的业务,新增,删除,再次新增就正常了。
完整代码github
EF Core 中处理 1对1 关系的更多相关文章
- [小技巧]EF Core中如何获取上下文中操作过的实体
原文地址:https://www.cnblogs.com/lwqlun/p/10576443.html 作者:Lamond Lu 源代码:https://github.com/lamondlu/EFC ...
- 9.翻译系列:EF 6以及EF Core中的数据注解特性(EF 6 Code-First系列)
原文地址:http://www.entityframeworktutorial.net/code-first/dataannotation-in-code-first.aspx EF 6 Code-F ...
- 9.4 翻译系列:EF 6以及 EF Core中的NotMapped特性(EF 6 Code-First系列)
原文链接:http://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-f ...
- 12.翻译系列:EF 6 中配置一对多的关系【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-f ...
- EF Core 中多次从数据库查询实体数据,DbContext跟踪实体的情况
使用EF Core时,如果多次从数据库中查询一个表的同一行数据,DbContext中跟踪(track)的实体到底有几个呢?我们下面就分情况讨论下. 数据库 首先我们的数据库中有一个Person表,其建 ...
- EF Core中如何正确地设置两张表之间的关联关系
数据库 假设现在我们在SQL Server数据库中有下面两张表: Person表,代表的是一个人: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ...
- EF Core 2.1 支持数据库一对一关系
在使用EF Core和设计数据库的时候,通常一对多.多对多关系使用得比较多,但是一对一关系使用得就比较少了.最近我发现实际上EF Core很好地支持了数据库的一对一关系. 数据库 我们先来看看SQL ...
- EF Core中如何通过实体集合属性删除从表的数据
假设在数据库中有两个表:Person表和Book表,Person和Book是一对多关系 Person表数据: Book表数据: 可以看到数据库Book表中所有的数据都属于Person表中"F ...
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
项目开发中的一些注意事项以及技巧总结 1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...
随机推荐
- docker概念
一.docket概述 什么是docker? 为什么docker会出现 一款产品从开发到上线,从操作系统,到运行环境,再到应用配置.作为开发+运维之间的协作我们需要关心很多东西,这也是很多互联网公司都不 ...
- 07-kubernetes Ingress 原理 和 Ingress-nginx 案例
目录 Service 类型 namespace 名称空间 Ingress Controller Ingress Ingress-nginx 进行测试 创建对应的后端Pod和Service 创建 Ing ...
- 02-kubeadm初始化Kubernetes集群
目录 部署 组件分布 部署环境 kubeadm 步骤 基础环境 基础配置 安装基础组件 配置yum源 安装组件 初始化 master 导入镜像 执行命令: 查看组件状态 查看node状态 安装flan ...
- python内存-fromkeys
fromkeys 这个方法涉及到可变不可变类型,记录下测试代码 不可变类型 #可变类型-list x=["zx","zx2","zx3"] ...
- 把Git Repository建到U盘上去
Git很火.原因有三: 它是大神Linus Torvalds的作品,天然地具备神二代的气质和品质: 促进了生产力的发展,Git的分布式版本控制理念,并非首创,但非常适合开源社区的协作方式(不存在mas ...
- IT网址 插件 系统 软件 网址收集!
http://www.css88.com http://www.runoob.com/jquery/jquery-plugin-validate.html http://www.iteye.com/n ...
- Spring Boot 自动装配(二)
目录 目录 前言 1.起源 2.Spring Boot 自动装配实现 2.1.@EnableAutoConfiguration 实现 2.1.1. 获取默认包扫描路径 2.1.2.获取自动装配的组件 ...
- tensorflow学习笔记——AlexNet
1,AlexNet网络的创新点 AlexNet将LeNet的思想发扬光大,把CNN的基本原理应用到了很深很宽的网络中.AlexNet主要使用到的新技术点如下: (1)成功使用ReLU作为CNN的激活函 ...
- 【并发技术16】线程同步工具Exchanger的使用
如果两个线程在运行过程中需要交换彼此的信息,比如一个数据或者使用的空间,就需要用到 Exchanger 这个类,Exchanger 为线程交换信息提供了非常方便的途径,它可以作为两个线程交换对象的同步 ...
- chrome浏览器通过ajax的POST请求报403解决方法
方法1 把POST改成GET方式 方法2 添加请求格式contentType:“application/json”,