引言
经过前期的准备工作,.net core 3.1的运行环境和WEB服务器已经搭建完毕,这里需要注意一下,达梦DM8数据库对于Entity Framework Core 3.1 的驱动在NuGet官方源上并没有正式发布,需要从Win64安装版本中的drivers/dotNet
提取,这里需要事先准备。
创建项目
出于开发的习惯和便利性,项目的开发和调试都还是在windows的环境下面进行,打开Visual Studio 2019,创建新项目,使用ASP.NET Core web应用程序
模板,项目名称自己取一下,我这里取名DmExample
,版本选择ASP.NET Core 3.1
,为HTTPS 配置
勾选去掉,暂时不需要HTTPS
点击”创建“按钮后,稍微等待一会儿,默认的MVC项目搭建完成。在Controllers
目录下只有一个HomeController.cs
文件,点击运行看一下:
已经可以正常跑起来,接下来我们要在这个基础下开始添加模型、连接达梦数据库、创建数据库、添加简单的增删改查的操作。
添加驱动
在添加应用之前,为了能够连接数据库和创建表,我们首先要使用NuGet包管理工具,安装如下支持包:
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.Design
安装完以上包后,我们需要安装EF Core的达梦数据库驱动,前面提到过在官方的NuGet源中并没有达梦的EF Core驱动,但在达梦的安装盘上有提供,所以需要对NuGet包管理器的程序包源进行添加设置,将达梦数据库安装源中的EFCore.Dm3.1
,DmProvider
作为包源引入,然后再安装。
在NuGet包管理器中,点击右上角(红框框起来的齿轮图标),弹出选项窗口:
点击窗口右上角的加号图标,然后名称输入EFCore.Dm3.1
,源路径选择你光盘镜像下面的source\drivers\dotNet\EFCore.Dm3.1
。以同样的方式将DmProvider
包源引入,源路径:source\drivers\dotNet\DmProvider
,包源设置完成后就可以安装。
如上图所示,选择程序包源EFCore.Dm3.1
后,在浏览面板中会列出达梦的EntityFramework Core的驱动包,选择它然后点击”安装“。
同样,选择程序包源DmProvider
后,在浏览面板中会列出达梦的DmProvider的驱动包,选择它然后点击”安装“。这里有个地方需要注意,在NuGet包源上可以搜索到DmProvider 2.0
版本的包,虽然版本高于我们当前的本地版本,但这个是.NetFramework
版本的,于2017年9月7日发布,不适用于Core版本的,请不要安装或更新。
添加模型
驱动安装完成后,我们要添加一个数据模型,在Models
目录下添加一个User.cs
用户模型,具体代码如下:
using System;
using System.ComponentModel.DataAnnotations;
namespace DmExample.Models
{
///
/// 用户模型
///
public class User
{
public User()
{
Id = Guid.NewGuid().ToString("N");
CreateTime = DateTime.Now;
}
[Key]
public string Id { get; set; }
///
/// 姓名
///
public string Name { get; set; }
///
/// 年龄
///
public int? Age { get; set; }
///
/// 性别
///
public bool? Gender { get; set; }
///
/// 创建日期
///
public DateTime? CreateTime { get; set; }
}
}
属性不多,就ID、姓名、年龄、性别、创建日期,分别使用了字符串、整型、布尔型和日期类型,对一些常规性的属性做一下数据表属性对应测试。
创建数据库
添加数据库上下文
在项目中添加DbContext
目录,在目录中添加一个名为DmContext.cs
的类作为达梦数据库上下文,具体代码如下:
using DmExample.Models;
using Microsoft.EntityFrameworkCore;
namespace DmExample.DbContext
{
///
/// 达梦数据库上下文
///
public class DmContext : Microsoft.EntityFrameworkCore.DbContext
{
///
/// 用户
///
public DbSet Users { get; set; }
public DmContext(DbContextOptions options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity().ToTable("sys_user");
}
}
}
如上代码所示,DmContext
继承自Microsoft.EntityFrameworkCore.DbContext
,添加了用户User
的DbSet
,重载OnModelCreating
方法,将User
模型与数据库的sys_user
表建立映射关系,当然也可以不指定映射关系,在不指定的情况下,默认映射成Users
数据表。目前我们还没创建数据库,数据库里也还没有这个数据表,接下来需要配置数据库连接。
配置数据库连接
(1)添加数据库连接字符串
打开项目中的appsettings.json
配置文件,添加数据库连接字符串,如下所示:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DmExample": "Server=localhost;Database=DmExampleDB;User=SYSDBA;Password=111111;"
}
}
我们在appsettings.json
配置文件中添加了一个ConnectionStrings
的配置项,用来设置数据库连接字符串,连接字符串命名为DmExample
,字符串的格式同我们连接SqlServer类似,Server
为数据库地址、Database
为数据库名称、User
和Password
分别为连接数据库账号和密码,需要注意的一点是设置数据库地址的时候如果是本地地址,咱们往往习惯性地用Server=.
来表示,但是达梦数据库不认识这种表示,会无法连接数据库,需要把点替换成localhost
或127.0.0.1
才行,这个注意一下。
(2)注册数据库上下文
完成数据库连接字符串的添加后,我们需要在Starup.cs
类中对当前的数据库上下文进行注册,微软已经为我们提供上下文注册的中间件,只要调用它就可以了,具体代码如下:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// 注册DbContext
services.AddDbContext(options =>
options.UseDm(Configuration.GetConnectionString("DmExample")));
}
如上代码所示,DmContext
是咱们创建的达梦数据库上下文,DmExample
是我们在appsettings.json
配置文件中添加的数据库连接字符串,通过Configuration.GetConnectionString
方法获取该数据库连接字符串。这里注意这个代码:options.UseDm
,我们连接SqlServer
数据库的时候是使用options.UseSqlServer
,如果我们以后连接MySql
数据库时是使用options.UseMySQL
,使用不同的数据库需要对应的数据库驱动,UseDm
就是由达梦数据库驱动提供的方法,至此数据库的连接我们已配置完成,接下来我们要创建数据库。
创建数据库
数据库连接配置完成后,我们直接使用Visual Studio 2019的程序包管理器控制台,通过命令方式来创建数据库,首先输入如下命令(initDB是我们取的名字,没有强制规定):
add-migration 'initDB'
The add-migration command is one of the key commands in code first migrations. When you make changes to your domain model and need them dded into your database you create a new migration. This is done with the Add-Migration command. In it’s simplest form you need only toprovide a migration name.
add-migration命令是code first migration中的关键命令之一。当您对领域域模型进行更改并需要将它们时添加到数据库中,您将创建一个新的迁移。这是通过Add-Migration命令完成的。用最简单的形式,你只需要提供迁移名称。
命令执行成功后会在当前的项目中创建Migrations
目录, 在这个目录中我们发现有两个文件,其中一个文件由当前创建日期加上我们之前add 后面创建名字的一个记录20201002080053_initDB
记录了此次更新的部分,由于我们是第一次初始化,所以里面记录了全部表结构内容,下次我们再次使用该命令做更新时,会再次添加新的记录文件,只记录更新部分;另一个名为 DmContextModelSnapshot
的文件是 Migrations生成的IModel状态的快照的基类,里面记录了要生成db的内容。
接下来执行更新数据库命令:
update-database
出现如上图所示表示执行成功,为验证是否创建数据表,我们打开达梦的数据库管理工具,查看数据库是否已存在:
我们在模式->SYSDBA->表
下面发现了sys_user
这张表,在表空间->MAIN->表
也能够看到这张表。数据表应该是创建成功了,但是就是没有发现我们在数据库连接字符串中指定的数据库名DmExampleDB
,估计是达梦的数据库结构和SqlServer有所区别,这个放在后面系统性地再去学习了,至此我们数据库创建完毕,接下来开始添加针对用户的CURD操作了。
添加增删改查操作
我们选中项目中的Controllers
目录,点击右键弹出下拉菜单依次点击添加->控制器
,弹出添加已搭建基架的新项窗口,选择”视图使用Entity Framework的MVC控制器“,然后点击”确定“按钮,如下图所示:
点击”确定“按钮后弹出添加视图的配置窗口,模型类选择User
,数据上下文类选择DmContext
,控制器名称默认UsersController
,然后点击"添加"按钮。
稍微等待片刻后,我们看到在Controllers
目录中已经生成了UsersController
类,打开这个类文件,增删改查的代码都已经生成;点开Views
视图目录,下面新增了Users
目录,在该目录里边增删改查的视图也已全部生成。
用户操作的功能基本都有了,我们稍作改造就可以使用了。首先,我们要在首页上添加用户的User
的入口菜单,以便对用户进行操作,打开Views/Shared/_Layout.cshtml
,添加如下图代码:
另外,我们在User
模型类中添加了构造函数,对新建的User对象的Id和CreateTime,设置了默认值,所以我们在创建的时候就不必要再输这两个值了,编辑Views/Users/Create.cshtml
,去掉这两个属性的代码:
编辑Views/Users/Edit.cshtml
,将编辑CreateTime
的输入框修改为隐藏类型,编辑的时候不需要输入了:
最后,我们再修改一下Views/Users/Index.cshtml
,在列表页里添加ID列,把它显示出来:
至此我们代码修改完毕。
测试运行
完成以上的创建和修改,我们直接在本机上先测试运行一下,页面效果如下:
首页上多了一个User
菜单,我们点击这个菜单项后,显示如下页面:
这个是用户列表页面,因为我们还未添加任何用户,所以当前列表是空的。我们点击"Create New"链接,跳转至添加用户的页面,来添加一个新用户试试:
注意:性别是布尔类型的,我们输入true
或false
来表示,点击Create
按钮添加用户,成功后自动跳转到用户列表页面,如下图所示:
添加完成后,列表页面上显示出了一条记录,为了印证记录已经插入到sys_user
表里,我们打开达梦的数据库管理工具进行查看:
接下来,我们再测试一下编辑、详细、删除操作,也都没有问题,这里不再贴图,到此我们完成了简单的测试,下一步将项目先发布到本地,然后部署到Web服务器上。
注意,我们发布的时候需要修改一下数据库的连接字符串,连接地址要修改为服务器上的数据库,然后在程序包管理器控制台上再次运行update-database
命令,主要目的是在服务器上创建数据库,当然如果已经创建了就不用去执行这个命令了。然后,依次点击生成->发布DmExample
,弹出发布配置窗口,发布目标选择”文件夹“:
文件夹位置默认即可,然后点击”完成“按钮
摘要处默认即可,点击"发布"按钮,完成发布操作,系统会将编译的发布版本复制到指定的目标位置。
项目部署
项目的部署请参考《国产化之路-安装WEB服务器》章节中的”发布站点“,这里不再详细介绍,这里补充一项,在发布站点的时候我们需要配置反向代理,ASP.NET Core默认发布的端口号是5000
,所以在配置节中我们设置的端口号对应的也是5000
,但当我们的Web服务器发布多个站点时,不能使用同一个端口,那么我们如何去修改ASP.NET Core默认发布的端口号呢?经查阅资料,我们只需要在appsettings.json
的配置文件里添加urls
配置属性即可,具体如下:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DmExample": "Server=localhost;Database=DmExampleDB;User=SYSDBA;Password=dx2263111;"
},
"urls": "http://localhost:5005"
}
我们这里设定的默认端口为5005
,然后在Web服务器里对该站点的反向代理中的端口号做相应的调整:
# DmExample
location / {
proxy_pass http://localhost:5005;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
一切准备就绪,在Web服务器上发布完成后,打开站点显示正常,但是当我们插入一条用户数据后报错了。
纠错
同一个站点,在我们的开发机上测试都没有问题,然后发布到统信的操作系统下就出问题,接着又试了一下将数据库连到Web服务器,运行环境还是在开发机上试了一下也没有问题,应该来讲大概率就是环境问题了,那环境问题导致哪里出问题了呢?上面的错误信息,并没有告诉我们问题出在哪里,大概意思是讲让我们切换成开发模式可以查看到更详细的错误信息,那么我们切换成开发模式看看,暂停这个站点的守护进程,使用终端进入站点目录执行下面命令:
# 切换成"Development"模式
export ASPNETCORE_ENVIRONMENT=development
# 运行站点
dotnet DmExample.dll
然后使用浏览器打开该站点,执行用户插入操作,页面显示信息变成如下显示:
反馈的应该是插入的某个字段数据类型不对,原本输入的是数字的位置输入了非数字的字符,导致无法插入造成的,但未给出具体是哪个字段,分析我们当前的用户数据类型也就只有年龄是数字类型的,但这个有点不太可能,我们输入的确实是数字,其它和数字搭边的就是日期类型了。我们对这两个字段做了排查,结果发现是日期类型DateTime
的原因,那为什么会这样呢?我们做一个简单的日期类型输出然后分别在开发机上和Web服务器上去运行试试看,结果如下:
上图第一张是在windows开发机上输出,第二张是在统信UOS上输出。第一个时间是DateTime.Now
输出,第二个时间是特定时间输出,主要目的是为区分上下午。很明显看到,在开发机上是24小时格式的,但统信UOS是12小时格式的,并用中文标识出了上午
、下午
,在插入的时候就现了问题,但看了统信UOS时间设置也是24小时制的,网上找了一下,这个问题并不是只是统信UOS独有的,在Linux上都有这个问题,找了一下解决办法,需要在程序开始时设置CultureInfo.DefaultThreadCurrentCulture
,我们可以把它加在Program
的Main
入口上,代码如下:
public static void Main(string[] args)
{
// 跨平台 DateTime 中文 上午 下午 解决方案
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("zh-CN", true)
{
DateTimeFormat = { ShortDatePattern = "yyyy-MM-dd",
FullDateTimePattern = "yyyy-MM-dd HH:mm:ss", LongTimePattern = "HH:mm:ss" }
};
CreateHostBuilder(args).Build().Run();
}
CultureInfo.DefaultThreadCurrentCulture
属性用来 获取或设置当前应用程序域中线程的默认区域性,从上面的代码理解是,将其设置中文区域,然后指定了短日期、完整时间以及长时间的格式,这里注意HH
和hh
的区别,HH
是24小时制的,而hh
是12小时制的。我们在日期输出小例子里加上这一段代码然后再看看其在来个系统统上的输出是怎么样的:
上图第一张是windows开发机,第二张是统信UOS,我们发现时间格式已经和开发机上格式一致了,然后我们再次发布站点,进行测试,问题解决。
小结
通过以上的简单案例,我们实现了在统信UOS操作系统,基于达梦D8数据库,使用.net core 3.1和EntityFramework core的简单增、删、改、查的操作,在这个过程中我们发现windows和Linux类操作系统日期显示格式的不同对我们所开发的应用造成的影响,这个问题应该并不是统信UOS独有的问题。我们当前只是个开端,随着业务的深入,所遇到的问题也将会越来越复杂,具体问题需要具体分析,不管是什么样的问题我们相信都有解决办法。
参考资料
- DateTime中文上午下午解决方案:
- CultureInfo.DefaultThreadCurrentCulture属性介绍:https://docs.microsoft.com/zh-cn/dotnet/api/system.globalization.cultureinfo.defaultthreadcurrentculture?view=netcore-3.1
- 在 ASP.NET Core 中使用多个环境:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/environments?view=aspnetcore-3.1
- EF Core连接达梦数据库参考1:
- EF Core连接达梦数据库参考2: