如何使用 abp 创建 module 并应用单独的数据库迁移

最近在学习使用 abp 来做一些小程序。abp 是一个功能丰富的 .NET 开发框架,完全开源,遵循 DDD(领域驱动)设计模式,支持微服务开发,集成了 Identity、角色权限、本地化、动态代理、后台任务、分布式消息、审计日志、多租户支持等多个组件和特性,并提供了 Blazor 和 Angular 的前台页面。基于此框架可以遵循最佳实践,省去自己开发脚手架的时间,提升开发效率。但因为 abp 封装了非常多的功能,有时候需要花时间研究其配置,才能更好地发挥效能。

abp 的一个优势是模块化,可以在框架基础上开发出一个个的 module,以方便重用。国内 .NET 社区里已经开发出了非常多的模块,官方也提供了集成了很多模块的商业版。对我来说,使用模块解决的一个问题是,abp 升级非常频繁,如果将我的业务系统做成模块,能够更好的与框架本身进行隔离,这样以后框架升级的时候就无需担心对业务系统有破坏性的更改。本文介绍了如何开发一个模块,并使用单独的数据库及实现迁移。

创建 abp 项目

官方文档已经提供了非常详细的新建项目向导。参考:https://docs.abp.io/en/abp/latest/Getting-Started-Create-Solution?UI=Blazor&DB=EF&Tiered=Yes

CLI 命令参考:https://docs.abp.io/en/abp/latest/CLI

我们使用 abp CLI 创建一个新项目。我使用 Blazor 来开发前端页面,正好学一下。

abp new MainApp -u blazor

然后按照官方文档操作即可:https://docs.abp.io/en/abp/latest/Getting-Started-Running-Solution?UI=Blazor&DB=EF&Tiered=Yes

主要步骤是:

  • 修改数据库连接字符串

  • 运行 .DbMigrator 项目初始化数据库并填充初始数据。

  • 运行 .HttpApi.Host  项目

如果操作正确,我们应该能够看到 Swagger 文档了。

如果同时启动 .HttpApi.Host.Blazor 项目,前端页面也应该可以正常展示。基本的用户登录、角色权限都有了。

创建一个新模块

刚开始我是用 CLI 创建了一个新模块,然后手动把两个项目的 solution 文件集成到一块,麻烦而且易出错。后来发现原来 CLI 已经提供了将新模块添加到现有解决方案的命令,可参考:https://docs.abp.io/en/abp/latest/CLI#options-3

可以使用以下的命令:

abp add-module MyModule --new --add-to-solution-file

注意运行该命令的时候要在 MainApp 的目录下。这样 CLI 会在当前目录下创建一个 modules 目录来存放新模块的解决方案,同时把所有项目添加到 MainApp 的解决方案中,还会修改一些文件,这样我们就不用手动集成模块了。

添加新 Model

接下来继续按照官方文档来添加新的 Model:https://docs.abp.io/en/abp/latest/Tutorials/Part-1

具体内容这里就不展开了,可根据实际需要添加几个 Model。

步骤大概是:

  • 添加 Model

  • 更新模块 MyModule.EntityFrameworkCore 项目中的 MyModuleDbContext.cs 文件,添加相应的 DbSet

  • MyModuleDbContextModelCreatingExtensions.cs 中添加模型映射

为模块准备数据库迁移

接下来就是本文的重点,如何为模块添加一个单独的数据库并实现数据库迁移。

首先在 MainApp.EntityFrameworkCore 项目中添加目录 EntityFrameworkCore\MyModule。在这个目录中创建一个名为 MyModuleMigrationsDbContext.cs 的文件。内容如下:

public class MyModuleMigrationsDbContext : AbpDbContext<MyModuleMigrationsDbContext>{public MyModuleMigrationsDbContext(DbContextOptions<MyModuleMigrationsDbContext> options) : base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.ConfigureMyModule();}}

然后添加一个名为 MyModuleMigrationsDbContextFactory.cs 的文件:

public class MyModuleMigrationsDbContextFactory : IDesignTimeDbContextFactory<MyModuleMigrationsDbContext>{public MyModuleMigrationsDbContext CreateDbContext(string[] args){var configuration = BuildConfiguration();var builder = new DbContextOptionsBuilder<MyModuleMigrationsDbContext>().UseSqlServer(configuration.GetConnectionString("MyModule"));return new MyModuleMigrationsDbContext(builder.Options);}private static IConfigurationRoot BuildConfiguration(){var builder = new ConfigurationBuilder().SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../MainApp.DbMigrator/")).AddJsonFile("appsettings.json", optional: false);return builder.Build();}}

这两个文件与 MainApp 的 DbContext 内容是类似的,大家可以比较一下。因为模块也要从 appsettings.json 中读取数据库配置,因此我们需要修改 appsettings.json 中的数据库链接字符串,注意需要修改两个位置:一个是 MainApp.DbMigrator 项目中的,另一个是 MainApp.HttpApi.Host 项目中的。仿照 MainApp 的连接字符串添加一个名为 MyModule 的即可。这样模块就可以有一个单独的数据库了。

运行模块数据库迁移

创建了新的 Model 后,我们要对数据进行迁移,以应用这些更改。

将 terminal 导航到 MainApp.EntityFrameworkCore 目录,运行以下命令:

dotnet ef migrations add migrationName --context MyModuleMigrationsDbContext --output-dir Migrations/MyModule

注意要指定要迁移的 DbContext,也就是 MyModuleMigrationsDbContext。同时我们还将迁移文件放在 Migrations/MyModule 目录下,这样不会与 MainApp 的迁移文件混淆。

如果一切正常,我们就可以在指定目录下看到生成的迁移文件了。

运行以下命令以应用数据库迁移:

dotnet ef database update --context MyModuleMigrationsDbContext

这样模块的数据库迁移就完成了。

其他设置

接下来按照官方文档继续添加相应的 AppService 及其接口等。这样我们的模块已经与 MainApp 是隔离的了,包括 Blazor 页面也是在一个单独的项目里。

如果运行 .HttpApi.Host 没有看到模块的 API,可以检查下 MainApp.HttpApi.Host 项目中的 MainAppHttpApiHostModule.cs 文件,看是否配置正确:

private void ConfigureConventionalControllers(){Configure<AbpAspNetCoreMvcOptions>(options =>{options.ConventionalControllers.Create(typeof(MainAppApplicationModule).Assembly);// Add the below lineoptions.ConventionalControllers.Create(typeof(MyModuleApplicationModule).Assembly);});}

再次运行 .HttpApi.Host.Blazor 项目,可以看到前端页面已经添加了一个新模块的链接,只是内容页是空的。接下来我们就可以在 MyModule 解决方案里的 Blazor 项目中开发前端页面了。

在添加 Model 后我还遇到过一个错误,如下图所示:

1d0fd36f82ec9d04a6af5d4e5285ced1.png

Autofact.Core.DependencyResolutionException: 'An exception was thrown while activating Volo.Abp.IdentityServer.Grants.PersistedGrantStore ....'

乍一看还以为是 IdentityServer 的问题,其实不是。展开看 inner exception 就会发现这个是我们添加的 Dto 的 mapping 导致的。因为 Entity 是有 Id 的,但 CreateUpdateProductDto 没有Id,所以 mapping 出错了。如果遇到这种情况,可以将 Id 省略掉:

CreateMap<CreateUpdateProductDto, Product>().Ignore(x => x.Id);

学习了几天感觉这个框架还是挺方便的,功能非常强大,但学习起来还是有一定难度的。框架各部分之间的依赖非常多,如果不仔细研究,很容易处处碰壁。好在官方文档写的还是相对比较详细的,只是部分文档还有空缺。希望官方以后补足吧。是否使用框架开发是一个两难的问题,太依赖框架可能会失去对细节的把控,处处受制于框架的实现;不使用框架就得自己重复造轮子。只能见仁见智了。

5eaa0ffffeb3d2c6d9068dff2c2870f9.png

万水千山总是情,点个关注行不行

天若有情天亦老,加个粉丝好不好

15e82b053a1c4ca93360bb7c8ed038f5.png

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

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

相关文章

MinGW安装和使用基础教程

MinGW全称Minimalist GNU For Windows&#xff0c;是个精简的Windows平台C/C、ADA及Fortran编译器&#xff0c;相比Cygwin而言&#xff0c;体积要小很多&#xff0c;使用较为方便。MinGW提供了一套完整的开源编译工具集&#xff0c;以适合Windows平台应用开发&#xff0c;且不依…

px,em,rem,vw单位在网页和移动端的应用

px&#xff1a; 是网页设计中最常用的单位&#xff0c;然而1px到底是多大长&#xff0c;恐怕没有人能回答上来 它用来表示屏幕设备物理上能显示的最小的一个点&#xff0c;这个点不是固定宽度的&#xff0c;不同设备上点的长度、比例有可能会不同。 假设&#xff1a;你现在用的…

cs-Panination

ylbtech-Unitity: cs-PaninationPager.cs IPagingOption.cs IPagedList.cs PagingOption.cs PagedList.cs PagingExtensions.cs 1.A,效果图返回顶部 1.B,源代码返回顶部1.B.1,Pager.cs using System; using System.Collections.Generic; using System.Linq; using System.Text…

SignalR的使用

什么是 SignalR&#xff1f;ASP.NET Core SignalR 是一个开放源代码库&#xff0c;可用于简化向应用添加实时 Web 功能。实时 Web 功能使服务器端代码能够将内容推送到客户端。适合 SignalR 的候选项&#xff1a;需要从服务器进行高频率更新的应用。示例包括游戏、社交网络、投…

NHibernate之旅(7):初探NHibernate中的并发控制

本节内容 什么是并发控制&#xff1f; 悲观并发控制(Pessimistic Concurrency)乐观并发控制(Optimistic Concurrency)NHibernate支持乐观并发控制实例分析结语什么是并发控制&#xff1f; 当很多人试图同一时候改动数据库中的数据时&#xff0c;必须实现一个控制系统&#xff0…

期望DP

期望DP的一般做法是从末状态開始递推&#xff1a; Problem DescriptionAkemi Homura is a Mahou Shoujo (Puella Magi/Magical Girl).Homura wants to help her friend Madoka save the world. But because of the plot of the Boss Incubator, she is trapped in a labyrinth …

神奇的[Caller*]属性

前言上次&#xff0c;我们《使用 CallerArgumentExpression 检查弃元参数》&#xff0c;它实际是利用编译器编译时将变量名称传入。其实&#xff0c;.NET中提供了多个[Caller*]属性&#xff0c;帮助我们轻松获取调用者信息。CallerFilePathAttribute允许获取包含调用方的源文件…

java dateTime + long

2019独角兽企业重金招聘Python工程师标准>>> public static void main(String[] args) throws Exception{SimpleDateFormat sdfnew SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // long timeStartsdf.parse("2011-09-20 12:30:45").getTime();l…

.NET Core中异常过滤器ExceptionFilter的使用介绍

介绍实现需要继承IExceptionFilter 或 IAsyncExceptionFilter。可用于实现常见的错误处理策略。使用场景首先讲一下我们为什么要使用异常过滤器 &#xff0c;如果业务场景复杂&#xff0c;只使用HttpStatusCode&#xff0c;抛出异常后,后期要加很多字段来描述。那么这种就比较不…

程序一启动检查网络,如果没有网络就退出程序

转载于:https://www.cnblogs.com/songxing10000/p/4823812.html

看小说的这些年

从大一开始&#xff0c;就开始看起了小说&#xff0c;不是那种名著类型&#xff0c;而是快餐小说&#xff0c;玄幻、都市、言情、科幻&#xff0c;什么都会看&#xff0c;因为看多了&#xff0c;就会发现&#xff0c;已经没什么可以看的。 谈起快餐小说&#xff0c;已经有很多被…

COMA(一): Learning to Communicate with Deep Multi-Agent Reinforcement Learning 论文讲解

Learning to Communicate with Deep Multi-Agent Reinforcement Learning 论文讲解 论文链接&#xff1a;https://papers.nips.cc/paper/6042-learning-to-communicate-with-deep-multi-agent-reinforcement-learning.pdf &#xff08;这篇论文是COMA三部曲中的第&#xff08…

C和指针之指针数组和指向数组的指针

1、指针数组 定义一个指针数组&#xff0c;该数组中每个元素是一个指针&#xff0c;每个指针指向哪里就需要程序中后续再定义int *p[10]; 2、指向数组的指针 定义一个数组指针&#xff0c;该指针指向含10个元素的一维数组&#xff08;数组中每个元素是int型&#xff09;int (*p…

SSH 远程执行任务

SSH 是 Linux 下进行远程连接的基本工具&#xff0c;但是如果仅仅用它来登录那可是太浪费啦&#xff01;SSH 命令可是完成远程操作的神器啊&#xff0c;借助它我们可以把很多的远程操作自动化掉&#xff01;下面就对 SSH 的远程操作功能进行一个小小的总结。远程执行命令如果我…

分库分表之历史表如何选择最佳分片路由规则

前言先别急着关闭,我相信这篇文章应该是所有讲分表分库下的人都没有和你们讲过的一种分片模式,外面的文章基本上都是教你如何从零开始分片,现在我将讲解的是如何从1开始分片项目地址github地址 https://github.com/dotnetcore/sharding-coregitee地址 https://gitee.com/dotnet…

COMA(二):Counterfactual Multi-Agent Policy Gradients 论文讲解

Counterfactual Multi-Agent Policy Gradients 论文链接&#xff1a;https://arxiv.org/pdf/1705.08926.pdf 1. 问题提出&#xff08;解决了什么问题&#xff1f;&#xff09; 在现实世界中&#xff0c;有非常多的问题需要多个单位之间的“合作”才能完成任务&#xff0c;这就…

lecture6-mini批量梯度训练及三个加速的方法

Hinton的第6课&#xff0c;这一课中最后的那个rmsprop&#xff0c;关于它的资料&#xff0c;相对较少&#xff0c;差不多除了Hinton提出&#xff0c;没论文的样子&#xff0c;各位大大可以在这上面研究研究啊。 一、mini-批量梯度下降概述 这部分将介绍使用随机梯度下降学习来训…

Dapr集成之GRPC 接口

Dapr 为本地调用实现 HTTP 和 gRPC API 。通常大家第一时间想到的是通过 gRPC 调用 Dapr&#xff0c;更重要的一点是Dapr 也可以通过 gRPC 与应用程序通信。要做到这一点&#xff0c;原理很简单&#xff0c;应用程序需要托管一个gRPC服务器&#xff0c;并实现 Dapr 的GRPC 规范…

jQuery Validate验证框架详解

jQuery Validate验证框架详解 jQuery校验官网地址&#xff1a;http://bassistance.de/jquery-plugins/jquery-plugin-validation 一、导入js库 <script type"text/javascript" src"<%path %>/validate/jquery-1.6.2.min.js"></script> &…

RNN入门笔记

本笔记来源自Youtube李宏毅老师的RNN视频归纳&#xff0c;主要分为以下几个知识点: RNN 的特点RNN 的几种实现方法 (Simple RNN, LSTM)RNN 的训练不稳定性RNN 的keras实现 (定长和变长输入案例) Recurrent Neural Network Feature of RNN Differ from normal Neural Networ…