外键拆分手记

yizhihongxing

我习惯性使用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/p/17357900.html

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

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

相关文章

  • C#如何优雅的对WinForm窗体应用程序进行权限控制

    C#中对WinForm窗体应用程序进行权限控制的优雅方法主要有以下几个步骤: 1. 创建用户登录界面 在用户打开程序时,首先需要提供一个登录窗口,将用户的账号和密码发送给服务器验证。可以使用WinForm中的TextBox、Label和Button等工具来创建这个窗口。 2. 向接口获取用户权限信息 用户登录成功后,需要将用户的身份信息发送给服务器来获取用户…

    C# 2023年5月31日
    00
  • win10下ASP.NET Core部署环境搭建步骤

    win10下ASP.NET Core部署环境搭建步骤 ASP.NET Core是一个跨平台的开源Web框架,可以在Windows、Linux和macOS等操作系统上运行。在本攻略中,我们将介绍如何在Windows 10操作系统上搭建ASP.NET Core部署环境,并提供两个示例说明。 1. 安装.NET Core SDK 在Windows 10操作系统上搭…

    C# 2023年5月16日
    00
  • asp.net创建位图生成验证图片类(验证码类)

    下面是“ASP.NET创建位图生成验证图片类(验证码类)”的完整攻略: 什么是验证码 验证码是为了防止机器人恶意攻击而设置的一种机制。它一般是一张由数字或字母组成的随机图片,用户需要在文本框中输入正确的验证码,才能通过验证并继续执行后续的操作。所以,验证码一般被用于用户登录、注册、评论等操作中,以保障网站安全。 创建验证码类 1. 准备工作 准备一个名为“V…

    C# 2023年5月31日
    00
  • C# Path.GetFullPath()方法: 获取指定路径的完整路径

    Path.GetFullPath() 方法的作用是将一个相对路径转换为完整的绝对路径,同时解析出该路径中的特殊字符和符号链接。 Path.GetFullPath() 方法有两个重载形式: public static string GetFullPath(string path); public static string GetFullPath(string…

    C# 2023年4月19日
    00
  • 什么是机器视觉?

    由于当前社会人力成本越来越昂贵,机器取代人力是大势所趋,自动化的发展也随之越来越快 。当制造公司需 要一双手和一对 眼睛的时候却不得不雇佣一个人的苦恼日益加重,而传统的机器设计和电气自动化的发展,解决一双手的问题已经渐渐得到了缓解,现在就到了需要解决一双眼睛的时候,机器视觉的出现和广泛应用也随着到来。 机器视觉是计算机科学的一个重要分支,它综合了光学,机械,…

    C# 2023年4月19日
    00
  • c#封装百度web服务geocoding api 、百度坐标转换示例

    下面是详细讲解“c#封装百度web服务geocodingapi、百度坐标转换示例”的完整攻略。 1.了解百度Web服务、GeoCodingAPI和坐标转换功能 在开始本教程之前,首先需要了解百度Web服务、GeoCodingAPI和坐标转换功能的作用。 1.1 百度Web服务 百度Web服务是百度提供的一种通过互联网进行信息传输的服务。通过百度Web服务,你…

    C# 2023年5月15日
    00
  • C# 递归函数详细介绍及使用方法

    C#递归函数详细介绍及使用方法 什么是递归函数? 递归函数是一种函数,它调用自身来解决问题。在编程中,递归函数通常用于解决计算机科学中的分治问题或数学归纳法中的问题。C#编程语言支持递归函数,并在解决某些问题时非常有用。 递归函数的工作原理 递归函数是基于递归的思想而设计的。其大致工作方式为:1. 函数调用自身2. 函数执行一些操作3. 递归函数达到结束状态…

    C# 2023年5月15日
    00
  • C#DirectoryInfo类用法详解

    C#DirectoryInfo类用法详解 什么是DirectoryInfo? DirectoryInfo是C#中用于操作文件夹的类,可以用来获取、创建、移动、重命名和删除文件夹等操作。 DirectoryInfo的基本使用方法 获取文件夹信息 要获取一个文件夹的信息,需要先实例化一个DirectoryInfo对象,并将要操作的文件夹的路径作为参数传入。 Di…

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