使用EF.Core将同一模型映射到多个表

在 EntityFramework Core 中,我们可以使用属性或Fluent API来配置模型映射。有一天,我遇到了一个新的需求,有一个系统每天会生成大量数据,每天生成一个新的表存储数据。例如,数据库如下所示:

所有表都具有相同的结构。那么,如何更改映射以避免创建多个模型呢?

在本文中,我将向您展示如何更改映射以处理这种情况。您也可以使用此方法扩展出更多的用法。

创建 .NET Core 3.1 项目

现在,我们可以使用.NET Core 3.1,它是.NET Core的LTS版本,将来可以轻松将其升级到.NET 5。

假设您已经在计算机上安装了最新的.NET Core SDK。如果没有,则可以从https://dotnet.microsoft.com/download下载。然后,您可以使用dotnet CLI创建项目。对于此示例,我将使用.NET Core 3.1。

让我们创建一个名为DynamicModelDemo的新.NET Core Console项目:

dotnet new console --name DynamicModelDemo

然后用以下命令创建一个新的解决方案:

dotnet new sln --name DynamicModelDemo

接下来使用以下命令把刚才创建的项目添加到解决方案:

dotnet sln add "DynamicModelDemo/DynamicModelDemo.csproj"

接下来可以用Visual Studio打开解决方案了。

创建模型

该模型非常简单。在项目中添加一个名为ConfigurableEntity.cs的新文件:

using System;namespace DynamicModelDemo
{public class ConfigurableEntity{public int Id { get; set; }public string Title { get; set; }public string Content { get; set; }public DateTime CreateDateTime { get; set; }}
}

我们将使用CreateDateTime属性来确定模型应该映射到哪个表。

添加 EntityFramework Core

导航到项目目录并使用以下命令添加所需的EF.Core packages:

dotnet add package Microsoft.EntityFrameworkCore.SqlSever
dotnet add package Microsoft.EntityFrameworkCore.Design

如果您还没有安装 ef tool,请运行以下命令来安装:

dotnet tool install --global dotnet-ef

这样您就可以使用 dotnet ef 工具创建迁移或通过应用迁移来更新数据库。

创建 DbContext

向项目添加一个名为DynamicContext.cs的新类文件。内容如下所示:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using System;namespace DynamicModelDemo
{public class DynamicContext : DbContext{public DbSet<ConfigurableEntity> Entities { get; set; }#region OnConfiguringprotected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)=> optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=DynamicContext;Trusted_Connection=True;");#endregion#region OnModelCreatingprotected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<ConfigurableEntity>(b =>{b.HasKey(p => p.Id);});}#endregion}
}

目前,这只是EF.Core的基本配置。它使用默认映射,这意味着模型将映射到名为Entities的表。那么,如果我们想基于其CreateDateTime属性将模型映射到不同的表,该怎么办呢?

您可能知道我们可以使用ToTable()方法来更改表名,但是如何在OnModelCreating方法中更改所有模型的表名呢?EF建立模型时,只会执行一次OnModelCreating。所以这种方式是无法实现的。

对于这种情况,我们需要使用IModelCacheKeyFactory来更改默认映射,通过这个接口我们可以定制模型缓存机制,以便EF能够根据其属性创建不同的模型。

IModelCacheKeyFactory是什么?

这是微软官方的文档解释:

EF uses IModelCacheKeyFactory to generate cache keys for models.

默认情况下,EF假定对于任何给定的上下文类型,模型都是相同的。但是对于我们的方案,模型将有所不同,因为它映射到了不同的表。因此,我们需要用我们的实现替换IModelCacheKeyFactory服务,该实现会比较缓存键以将模型映射到正确的表。

请注意,该接口通常由数据库提供程序和其他扩展使用,一般不在应用程序代码中使用。但是对于我们的场景来说,这是一种可行的方法。

实现IModelCacheKeyFactory

我们需要使用CreateDateTime来区分表。在DynamicContext类中添加一个属性:

public DateTime CreateDateTime { get; set; }

在项目中添加一个名为DynamicModelCacheKeyFactory.cs的新类文件。代码如下所示:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;namespace DynamicModelDemo
{public class DynamicModelCacheKeyFactory : IModelCacheKeyFactory{public object Create(DbContext context)=> context is DynamicContext dynamicContext? (context.GetType(), dynamicContext.CreateDateTime): (object)context.GetType();}
}

在生成模型缓存键时,此实现将考虑CreateDateTime属性。

应用IModelCacheKeyFactory

接下来,我们可以在上下文中注册新的IModelCacheKeyFactory

#region OnConfiguring
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)=> optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=DynamicContext;Trusted_Connection=True;").ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactory>();
#endregion

这样我们就可以在OnModelCreating方法中分别映射表名了:

#region OnModelCreating
protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.Entity<ConfigurableEntity>(b =>{b.ToTable(CreateDateTime.ToString("yyyyMMdd"));b.HasKey(p => p.Id);});
}
#endregion

CreateDateTime来自DynamicContext的属性。

我们可以在创建DynamicContext时指定CreateDateTime属性:

var context = new DynamicContext { CreateDateTime = datetime };

如果datetime2020/03/27,则context的模型将映射到名为20200327的表。

创建数据库

在验证代码之前,我们需要首先创建数据库。但是,EF迁移并不是这种情况的最佳解决方案,因为随着时间的流逝,系统将生成更多表。我们只是使用它来创建一些示例表来验证映射。实际上,系统应该具有另一种每天动态生成表的方式。

运行以下命令以创建第一个迁移:

dotnet ef migrations add InitialCreate

您会看到在Migrations文件夹中生成了两个文件。打开xxx_InitialCreate.cs文件,并通过以下代码更新Up方法:

protected override void Up(MigrationBuilder migrationBuilder)
{for (int i = 0; i < 30; i++){var index = i;migrationBuilder.CreateTable(name: DateTime.Now.AddDays(-index).ToString("yyyyMMdd"),columns: table => new{Id = table.Column<int>(nullable: false).Annotation("SqlServer:Identity", "1, 1"),Title = table.Column<string>(nullable: true),Content = table.Column<string>(nullable: true),CreateDateTime = table.Column<DateTime>(nullable: false)},constraints: table =>{table.PrimaryKey($"PK_{DateTime.Now.AddDays(-index):yyyyMMdd}", x => x.Id);});}}

所做的更改是为了确保数据库中可以有足够的表进行测试。请注意,我们不应该在生产环境中使用这种方式

接下来,我们可以使用此命令来创建和更新数据库:

dotnet ef database update

您会看到它在数据库中生成了最近30天的表。

验证映射

现在该验证新映射了。通过以下代码更新Program.cs中的Main方法:

static void Main(string[] args)
{DateTime datetime1 = DateTime.Now;using (var context = new DynamicContext { CreateDateTime = datetime1 }){context.Entities.Add(new ConfigurableEntity { Title = "Great News One", Content = $"Hello World! I am the news of {datetime1}", CreateDateTime = datetime1 });context.SaveChanges();}DateTime datetime2 = DateTime.Now.AddDays(-1);using (var context = new DynamicContext { CreateDateTime = datetime2 }){context.Entities.Add(new ConfigurableEntity { Title = "Great News Two", Content = $"Hello World! I am the news of {datetime2}", CreateDateTime = datetime2 });context.SaveChanges();}using (var context = new DynamicContext { CreateDateTime = datetime1 }){var entity = context.Entities.Single();// Writes news of todayConsole.WriteLine($"{entity.Title} {entity.Content} {entity.CreateDateTime}");}using (var context = new DynamicContext { CreateDateTime = datetime2 }){var entity = context.Entities.Single();// Writes news of yesterdayConsole.WriteLine($"{entity.Title} {entity.Content} {entity.CreateDateTime}");}
}

您将会看到如下输出:

现在,我们可以通过传递CreateDateTime属性来使用相同的DbContext来表示不同的模型了。

小结

该演示旨在演示如何使用IModelCacheKeyFactory更改默认模型映射。请注意,您仍然需要实现分别生成表的方法。托管服务是一种实现方式。有关更多信息,请访问Background tasks in ASP.NET Core[1]

参考资料

[1]

Background tasks in ASP.NET Core: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio

求赞赏

????????????

推荐阅读

  • 【手把手教程】如何让你的求职简历敲开新西兰雇主的大门(文末送福利)

  • 【手把手教程】新西兰求职,如何写好Cover Letter?

  • 再不拼老命我们就真老了——大龄码农DIY新西兰技术移民全记录

  • 移民路上为什么别人总能得到更多的信息,今天知道真相还不算太晚

  • 还在愁纽村的面试吗?安啦~史上最靠谱的面试题借你看两眼!

  • 雅思之路——只有绝境没有捷径

  • 身在中国,如何应对海外公司的电话面试?

  • 大龄码农来新西兰三个月拿到两个offer,真的只是运气好?

  • 找工作的本命年——从国内大厂到NZ大厂

  • 苦中有甜、笑中含泪的新移民生活——多的是你不知道的事

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310757.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EntityFramework Core 3.x添加查询提示(NOLOCK)

前几天看到有博客园中有园友写了一篇关于添加NOLOCK查询提示的博文&#xff0c;这里呢&#xff0c;我将介绍另外一种添加查询提示的方法&#xff0c;此方式源于我看过源码后的实现&#xff0c;孰好孰歹&#xff0c;请自行判之&#xff0c;接下来我们一起来看看。在EntityFramew…

Xamarin.Forms客户端第一版

1. 功能简介1.1. 读取手机基本信息主要使用Xamarin.Essentials库获取设备基本信息&#xff0c;Xam.Plugin.DeviceInfo插件获取App Id&#xff0c;其实该插件也能获取设备基本信息。1.2. 读取手机联系人信息Android和iOS工程具体实现联系人读取服务&#xff0c;使用到Dependency…

给 EF Core 查询增加 With NoLock

给 EF Core 查询增加 With NoLockIntroEF Core 在 3.x 版本中增加了 Interceptor&#xff0c;使得我们可以在发生低级别数据库操作时作为 EF Core 正常运行的一部分自动调用它们。例如&#xff0c;打开连接、提交事务或执行命令时。所以我们可以自定义一个 Interceptor 来记录执…

LeetCode 138 复制带随机指针的链表-中等

给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节点的值都设为其对应的原节点的值。新节点的 n…

ASP.NET Core分布式项目实战(业务介绍,架构设计,oAuth2,IdentityServer4)--学习笔记...

任务4&#xff1a;第一章计划与目录敏捷产品开发流程原型预览与业务介绍整体架构设计API 接口设计 / swaggerIdentity Server 4 搭建登录账号 API 实现配置中心任务5&#xff1a;业务介绍项目背景&#xff1a;基于人脉关系的金融行业项目用户&#xff1a;1、账号&#xff1a;基…

LeetCode 82 删除排序链表中的重复元素||-中等

存在一个按升序排列的链表&#xff0c;给你这个链表的头节点 head &#xff0c;请你删除链表中所有存在数字重复情况的节点&#xff0c;只保留原始链表中 没有重复出现 的数字。 返回同样按升序排列的结果链表。 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;[1,2,…

你复工了吗?啥感受?

这里是Z哥的个人公众号每周五11&#xff1a;45 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「136」篇原创敬上感觉还没做什么事情&#xff0c;2020年的第一季度就结束了。相信大多数人也都已经复工了。之前进行远程公办的&#xff0c;大多也都回到了原先在公…

LeetCode 1669合并两个链表-中等

给你两个链表 list1 和 list2 &#xff0c;它们包含的元素分别为 n 个和 m 个。 请你将 list1 中第 a 个节点到第 b 个节点删除&#xff0c;并将list2 接在被删除节点的位置。 下图中蓝色边和节点展示了操作后的结果&#xff1a; 请你返回结果链表的头指针。 输入&#xff1a…

dotNET Core 3.X 使用 Web API

现在的 Web 开发大多都是前后端分离的方式&#xff0c;后端接口的正确使用显得尤为重要&#xff0c;本文讲下在 dotNET Core 3.X 下使用 Web API 。环境操作系统&#xff1a;MacIDE&#xff1a;RiderdotNET Core&#xff1a;3.1创建项目如果是 Windows 操作系统当然是首选 VS20…

你需要了解的 HTTP Status Code

你需要了解的 HTTP Status CodeIntro现在前后端分离的开发模式越来越流行&#xff0c;后端负责开发对应的 API&#xff0c;前端只需要 关注前端页面的数据展示和前端逻辑即可。对于前后端分离这种开发模式&#xff0c;我个人还是比较喜欢的&#xff0c;因为这样可以让更专业的人…

LeetCode 24两两交换链表中的节点-中等

给定一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后的链表。 你不能只是单纯的改变节点内部的值&#xff0c;而是需要实际的进行节点交换。 输入&#xff1a;head [1,2,3,4] 输出&#xff1a;[2,1,4,3] 示例 2&#xff1a; 输入&#xff1a;head []…

2021中考高考成绩查询,2021中考

2021年浙江东阳中考查分入口暂未公布&#xff01;如有最新信息&#xff0c;中考网会第一时间发布&#xff0c;请中考生和家长及时关注中考网中考考试时间频道&#xff01; 编辑推荐&#xff1a; 2021年浙江省中考查分时间及入口汇总 2021年全国各省市中考查分时间及入2021-06-1…

今天网站都变成灰色了,这其中是怎么实现的?

“ 阅读本文大概需要 7 分钟。 ”今天是 2020 年 4 月 4 日&#xff0c;星期六&#xff0c;清明节。我们的国家经历了非常惨痛的时刻&#xff0c;很多英雄在救助他人的路上倒下&#xff0c;更有很多烈士英雄保卫人民的安危遇难&#xff0c;今天全国下降半旗&#xff0c;北京时间…

深圳市公务员考试计算机专业素养,深圳市考职位分析_公务员考试专业对照表...

2020深圳市公务员招录1069人公告已发布&#xff0c;报名时间&#xff1a;11月13日-19日16:00&#xff0c;报名入口&#xff1a;深圳市考试院专栏(http://hrss.sz.gov.cn/szksy/)或深圳市人事考试考生服务系统(以下简称考生服务系统&#xff0c;https://hrsstext.sz.gov.cn/ess/…

LeetCode 61旋转链表-中等

给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1,2,3] 输入&#xff1a;head [0,1,2], k 4 输出&#xff1a;[2,0,1] 提示&#xff1a; 链表中节点的数目在…

科个普:进程、线程、并发、并行

一、进程刘大胖打开电脑&#xff0c;想写点东西&#xff0c;于是打开WPS&#xff0c;突然又想和女朋友(反正我不信)聊聊天&#xff0c;就又打开了微信PC端&#xff0c;这时操作系统就会为这两个程序生成两个进程&#xff0c;如图&#xff1a;二、线程每个进程至少包含一个线程&…

LeetCode 19删除链表的倒数第N个节点-中等

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 进阶&#xff1a;你能尝试使用一趟扫描实现吗&#xff1f; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n …

EFCore查询语句生成流程、让EFCore支持批量Update/Delete/MergeInto

引子之前发现了一款叫 EFCore.BulkExtensions 的 nuget 包。里面提供了大量的 BulkInsertOrUpdateOrDelete 和 BatchUpdate 的拓展&#xff0c;可以很方便的解决批量更新和删除的问题&#xff0c;不用让 EFCore 一条一条的删除和更新。其中几个比较有用的函数签名是Task<int…

html程序国庆节祝福,2018国庆节祝福祖国的话

2018国庆节即将来袭~那么2018国庆节祝福祖国的话有哪些呢&#xff1f;今天语录大全网小编就为大家整理了一篇10.1国庆节祝福祖国的话语&#xff0c;分享给大家&#xff0c;在这里小编祝大家国庆节快乐1、【祖国是东方的明珠&#xff0c;是亚洲腾飞的巨龙&#xff0c;是地平线上…

【翻译】.NET 5 Preview2发布

在4月2日&#xff0c;发布了.NET 5.0 Preview2&#xff0c;这次发布对一些功能和性能做了相关的改进&#xff0c;同时后面也会实施5.0版本更多的功能&#xff0c;其中一些功能目前也dotnet/designs在.NET 5 Preview1中可以看到.NET 5里程碑中已经完成的建设任务&#xff0c;当然…