最近在开发记录感想功能的时候用到了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

不出意外的话,这个ItemId会是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==1Item新增/修改/删除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 关系的更多相关文章

  1. [小技巧]EF Core中如何获取上下文中操作过的实体

    原文地址:https://www.cnblogs.com/lwqlun/p/10576443.html 作者:Lamond Lu 源代码:https://github.com/lamondlu/EFC ...

  2. 9.翻译系列:EF 6以及EF Core中的数据注解特性(EF 6 Code-First系列)

    原文地址:http://www.entityframeworktutorial.net/code-first/dataannotation-in-code-first.aspx EF 6 Code-F ...

  3. 9.4 翻译系列:EF 6以及 EF Core中的NotMapped特性(EF 6 Code-First系列)

    原文链接:http://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-f ...

  4. 12.翻译系列:EF 6 中配置一对多的关系【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-f ...

  5. EF Core 中多次从数据库查询实体数据,DbContext跟踪实体的情况

    使用EF Core时,如果多次从数据库中查询一个表的同一行数据,DbContext中跟踪(track)的实体到底有几个呢?我们下面就分情况讨论下. 数据库 首先我们的数据库中有一个Person表,其建 ...

  6. EF Core中如何正确地设置两张表之间的关联关系

    数据库 假设现在我们在SQL Server数据库中有下面两张表: Person表,代表的是一个人: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ...

  7. EF Core 2.1 支持数据库一对一关系

    在使用EF Core和设计数据库的时候,通常一对多.多对多关系使用得比较多,但是一对一关系使用得就比较少了.最近我发现实际上EF Core很好地支持了数据库的一对一关系. 数据库 我们先来看看SQL ...

  8. EF Core中如何通过实体集合属性删除从表的数据

    假设在数据库中有两个表:Person表和Book表,Person和Book是一对多关系 Person表数据: Book表数据: 可以看到数据库Book表中所有的数据都属于Person表中"F ...

  9. 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获

    项目开发中的一些注意事项以及技巧总结   1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...

随机推荐

  1. 2019-2020-5 20199317《Linux内核原理与分析》第五周作业

    第4章 系统调用的三层机制(上) 1  用户态.内核态和中断 大多数程序员在写程序时很难离开系统调用,与系统调用打交道的方式是通过库函数的方式,库函数用来把系统调用给封装起来. 计算机的硬件资源是有限 ...

  2. pod install速度慢解决方案

    相信大家已经感受到pod install速度越来越慢了,网上提供了几种解决方案,但是都没有完全解决速度慢的问题. 使用国内镜像的Specs 在pod install时使用命令pod install - ...

  3. 性能达到原生 MySQL 七倍,华为云 Taurus 技术解读【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  4. 【集合系列】- 深入浅出的分析 Properties

    一.摘要 在集合系列的第一章,咱们了解到,Map 的实现类有 HashMap.LinkedHashMap.TreeMap.IdentityHashMap.WeakHashMap.Hashtable.P ...

  5. CF1236B Alice and the List of Presents

    题意翻译 有nn种物品和mm个背包,每种物品有无限个,现将若干个物品放到这些背包中,满足: 1.每个背包里不能出现相同种类的物品(允许有空背包): 2.在所有的mm个背包中,每种物品都出现过. 求方案 ...

  6. 手撕 JVM 垃圾收集日志

    下图是本篇的写作大纲,将从以下四个方面介绍怎么样处理 JVM 日志. 有准备才能不慌 想要分析日志,首先你得有日志呀,对不对.凡是未雨绸蒙总是没错的.所谓有日志的意思,你要把 JVM 参数配置好,日志 ...

  7. 使用.NET Core创建Windows服务 - 使用.NET Core工作器方式

    原文:Creating Windows Services In .NET Core – Part 3 – The ".NET Core Worker" Way 作者:Dotnet ...

  8. nginx编译安装配置模块大全

    使用configure命令配置构建.它定义了系统的各个方面,包括允许nginx用于连接处理的方法.最后,它会创建一个Makefile.该configure命令支持以下参数:--help 打印帮助信息. ...

  9. 度及拓扑图的使用-UESTC1958学霸周选课

    学霸周选课 Time Limit: 1000 MS     Memory Limit: 128 MB Submit Status 众所周知周大爷不仅编程了得,专业课成绩更是名列前茅,恰巧又到了选课的季 ...

  10. Docker系列-(3) Docker-compose使用与负载均衡

    上一篇文章介绍了docker镜像的制作与发布,本文主要介绍实际docker工程部署中经常用到的docker-compose工具,以及docker的网络配置和负载均衡. Docker-compose介绍 ...