外键拆分手记

我习惯性使用OData,它的$expand与层级查询非常好用,这个功能非常依赖于数据库的导航属性,也就是外键结构。最近想着把一个单体的系统拆分为多个小系统,首先需要处理外键依赖的问题。

多个服务各自有各自的数据库,数据库层面并不互通,也就无法使用外键约束。

我使用EF Core来描述数据库的结构,有两个实体类如下:


public class AD_Insect_Info
{
	[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
	public int Id {get;set;}
	public string Name { get; set; }
	public virtual List<AD_Insect_Datum> Results { get; set; }
}

public class AD_Insect_Datum
{
	[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
	public int Id { get; set; }
	public virtual AD_Insect_Info AttachDevice { get; set; }
	[NotMapped]
	public override string AttachId => AttachDevice.AttachDeviceId;
}

可以看到他们之间有一个导航属性,实现一个一对多的关系。如果系统是新系统,大可直接进行拆解,想怎么弄就怎么弄。但是对于已经有较多数据的现有系统,最好使用渐进拆分的方式。

思路:通过多次,每次只修改一点,维持对旧有系统的兼容性,并在完全拆分前保持系统高度可用,破坏性最小。

指定外键

跨数据库的访问,数据完整性不能由数据库通过外键实现,我们需要在应用层实现自己的逻辑。由于外键不存在,我们需要在数据表中有表示对外引用的字段。而对于导航属性而言,外键已经由EF Core自动建立,为了防止数据结构变化导致的问题,我们可以明确指定外键。

查询数据表结构

EF Core有默认的外键命名规则,通常是字段名+外键的字段名,对于本例,则是AttachDeviceId,保险起见,我们可以查询数据库获得外键列名称。

显式指定外键名称

导航属性的外键名字不是那么直观,我们可以使用EF Core的ForeignKey特性。

public class AD_Insect_Datum : AttachDataBase
{
	[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
	public int Id { get; set; }
	[ForeignKey("AttachDeviceId")]
	public virtual AD_Insect_Info AttachDevice { get; set; }
	public int AttachDeviceId { get; set; }
}

这样,这个对象Id就被显式指定了。

查询替代

前一步指定了外键,但是实际上并没有对EF Core表做任何更改,原来的程序可以正常运行,我们需要在这个基础上继续改造,将使用导航属性的地方修改一下。

public virtual async Task<IActionResult> Data(string key)
{
	return Ok(_context.AD_Insect_Data.Where(w => w.AttachDevice.Name == key));
}

修改为:

public virtual async Task<IActionResult> Data(string key)
{
	var instances = _context.AD_Insect_Infos.Where(w=>w.Name == key).Select(w=> w.Id).ToList();
	return Ok(_context.AD_Insect_Data.Where(w => instances.Contains(w.AttachDeviceId)));
}

这样就避免使用导航属性依赖。

我这里也没有使用连表查询方法,因为将来需要拆分。

删除外键

由于不再使用导航属性,可以安全地删除外键。注意,可能需要补充一些业务逻辑以确保数据库中的数据完整性。

拆分DbContext

将来DbContext将不再拥有AD_Insect_Infos,因此我们需要进一步拆分。

public virtual async Task<IActionResult> Data(string key)
{
	IEnumerable<int> instances = Foreign.GetList(key);
	return Ok(_context.AD_Insect_Data.Where(w => instances.Contains(w.AttachDeviceId)));
}

public class Foreign
{
	public IEnumerable<int> GetList(string key)
	{
		return _context.AD_Insect_Infos.Where(w=>w.Name == key).Select(w=> w.Id).ToList();
	}
}

上面代码表示大致的思路,请自行处理注入依赖等问题。

然后就是熟悉的动作了,将Foreign类作为一个数据服务,只要返回的类型是IEnumerable<int>就可以了,数据的来源可以是本身,也可以是外部的服务。

原文链接:https://www.cnblogs.com/podolski/archive/2023/04/27/17357900.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:外键拆分手记 - Python技术站

(0)
上一篇 2023年4月25日
下一篇 2023年4月27日

相关文章

  • 浅谈JavaScript Date日期和时间对象

    浅谈JavaScript Date日期和时间对象 什么是JavaScript Date日期和时间对象? JavaScript 是一种基于对象和事件驱动的脚本语言。Date 是 JavaScript 中处理日期和时间的对象。它提供了多种方法来格式化和操作日期和时间。 创建JavaScript Date日期和时间对象 可以使用 Date() 构造函数创建一个日期…

    C# 2023年5月15日
    00
  • C# FileSystemWatcher 在监控文件夹和文件时的使用方法

    C#中的FileSystemWatcher类可以用于监控文件夹和文件的变化,例如创建、修改、删除等操作。本文将提供使用FileSystemWatcher类的完整攻略,包括创建FileSystemWatcher对象、设置监控选项、处理事件、示例等。 创建FileSystemWatcher对象 要使用FileSystemWatcher类,需要创建一个FileSy…

    C# 2023年5月15日
    00
  • C#中Dictionary排序方式的实现

    下面我将为您详细讲解如何在C#中使用Dictionary进行排序。 1. Dictionary排序的基本原理 C#中的Dictionary是一种键值对集合,其中TKey为键类型,TValue为值类型。在默认情况下,Dictionary按照键的默认顺序进行排序,并且不支持按照值排序。但是,我们可以通过以下两种方式来实现Dictionary的排序: 自定义比较器…

    C# 2023年6月1日
    00
  • ActiveMQ在C#中的应用示例分析

    ActiveMQ是一款领先的Java消息中间件,可以在不同的编程语言和平台中实现异步通信和消息传递。在C#中,我们可以使用NMS API(Apache.NMS)来与ActiveMQ进行交互。 下面是使用ActiveMQ在C#中实现消息队列的两个示例。 示例1:实现消费者读取消息 首先,我们需要安装和配置ActiveMQ,并且启动ActiveMQ服务。假设Ac…

    C# 2023年5月15日
    00
  • C#程序员应该养成的程序性能优化写法

    下面我将为您详细讲解C#程序员应该养成的程序性能优化写法,包含一个完整的攻略以及两条示例说明。 攻略 1. 明确性能优化的目标 在进行性能优化之前,需要先明确性能优化的目标,以及需要优化的具体内容,例如响应时间、内存占用等。只有明确了目标,程序员才能有针对性地进行优化。 2. 使用高效的数据结构 对于大规模数据处理的情况,使用高效的数据结构可以极大地提高程序…

    C# 2023年6月1日
    00
  • 经典实例讲解C#递归算法

    经典实例讲解C#递归算法攻略 什么是递归算法 递归算法通过自身不断的调用自身来实现计算。它是一种比较常用的算法,可以用来解决很多复杂问题。 递归算法的特点 递归算法有以下几个特点: 递归调用必须有结束条件 函数调用自身 函数每次调用的参数不同 C#递归算法的示例 示例1:阶乘运算 阶乘是指一个数的阶乘是所有比它小的正整数的积。例如,5的阶乘为54321=12…

    C# 2023年6月6日
    00
  • 理解C#中的Lambda表达式

    理解C#中的Lambda表达式需要掌握以下几个方面: Lambda表达式的语法 Lambda表达式的使用场景和应用 Lambda表达式与委托的关系 Lambda表达式的方法推断和参数类型推断 接下来我会逐一讲解。 Lambda表达式的语法 Lambda表达式是一种匿名方法,它通常用于作为委托类型的参数或返回值,可以简化很多代码。Lambda表达式的语法如下:…

    C# 2023年6月6日
    00
  • 最全.NET Core 、.NET 5、.NET 6和.NET 7简介和区别

    .NET是一种用于构建多种应用的免费开源开发平台,可以使用多种语言,编辑器和库开发Web应用、Web API和微服务、云中的无服务器函数、云原生应用、移动应用、桌面应用、Windows WPF、Windows窗体、通用 Windows平台 (UWP)、游戏、物联网 (IoT)、机器学习、控制台应用、Windows服务。框架主要包括:.NET Framewor…

    C# 2023年4月18日
    00
合作推广
合作推广
分享本页
返回顶部