國產化之路-統信UOS + Nginx + Asp.Net MVC + EF Core 3.1 + 達夢DM8實現簡單增刪改查操作

專題目錄

國產化之路-統信UOS作業系統安裝
國產化之路-國產作業系統安裝.net core 3.1 sdk
國產化之路-安裝WEB伺服器
國產化之路-安裝達夢DM8資料庫
國產化之路-統信UOS + Nginx + Asp.Net MVC + EF Core 3.1 + 達夢DM8實現簡單增刪改查操作

引言

經過前期的準備工作,.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.1DmProvider作為包源引入,然後再安裝。

在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
{
    /// <summary>
    /// 用戶模型
    /// </summary>
    public class User
    {
        public User()
        {
            Id = Guid.NewGuid().ToString("N");
            CreateTime = DateTime.Now;
        }

        [Key]
        public string Id { get; set; }

        /// <summary>
        /// 姓名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 年齡
        /// </summary>
        public int? Age { get; set; }

        /// <summary>
        /// 性別
        /// </summary>
        public bool? Gender { get; set; }

        /// <summary>
        /// 創建日期
        /// </summary>
        public DateTime? CreateTime { get; set; }
    }
}

屬性不多,就ID、姓名、年齡、性別、創建日期,分別使用了字元串、整型、布爾型和日期類型,對一些常規性的屬性做一下數據表屬性對應測試。

創建資料庫

添加資料庫上下文

在項目中添加DbContext目錄,在目錄中添加一個名為DmContext.cs的類作為達夢資料庫上下文,具體程式碼如下:

using DmExample.Models;
using Microsoft.EntityFrameworkCore;

namespace DmExample.DbContext
{
    /// <summary>
    /// 達夢資料庫上下文
    /// </summary>
    public class DmContext : Microsoft.EntityFrameworkCore.DbContext
    {
        /// <summary>
        /// 用戶
        /// </summary>
        public DbSet<User> Users { get; set; }

        public DmContext(DbContextOptions<DmContext> options) : base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<User>().ToTable("sys_user");
        }
    }
}

如上程式碼所示,DmContext繼承自Microsoft.EntityFrameworkCore.DbContext,添加了用戶UserDbSet,重載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為資料庫名稱、UserPassword分別為連接資料庫帳號和密碼,需要注意的一點是設置資料庫地址的時候如果是本地地址,咱們往往習慣性地用Server=.來表示,但是達夢資料庫不認識這種表示,會無法連接資料庫,需要把點替換成localhost127.0.0.1才行,這個注意一下。

(2)註冊資料庫上下文

完成資料庫連接字元串的添加後,我們需要在Starup.cs類中對當前的資料庫上下文進行註冊,微軟已經為我們提供上下文註冊的中間件,只要調用它就可以了,具體程式碼如下:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    // 註冊DbContext
    services.AddDbContext<DmContext>(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”鏈接,跳轉至添加用戶的頁面,來添加一個新用戶試試:

注意:性別是布爾類型的,我們輸入truefalse來表示,點擊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": "//localhost:5005"
}

我們這裡設定的默認埠為5005,然後在Web伺服器里對該站點的反向代理中的埠號做相應的調整:

# DmExample
location / {
	proxy_pass         //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,我們可以把它加在ProgramMain入口上,程式碼如下:

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屬性用來 獲取或設置當前應用程式域中執行緒的默認區域性,從上面的程式碼理解是,將其設置中文區域,然後指定了短日期、完整時間以及長時間的格式,這裡注意HHhh的區別,HH是24小時制的,而hh是12小時制的。我們在日期輸出小例子里加上這一段程式碼然後再看看其在來個系統統上的輸出是怎麼樣的:

上圖第一張是windows開發機,第二張是統信UOS,我們發現時間格式已經和開發機上格式一致了,然後我們再次發布站點,進行測試,問題解決。

小結

通過以上的簡單案例,我們實現了在統信UOS作業系統,基於達夢D8資料庫,使用.net core 3.1和EntityFramework core的簡單增、刪、改、查的操作,在這個過程中我們發現windows和Linux類作業系統日期顯示格式的不同對我們所開發的應用造成的影響,這個問題應該並不是統信UOS獨有的問題。我們當前只是個開端,隨著業務的深入,所遇到的問題也將會越來越複雜,具體問題需要具體分析,不管是什麼樣的問題我們相信都有解決辦法。

參考資料

DateTime中文上午下午解決方案://blog.csdn.net/i2blue/article/details/105798392

CultureInfo.DefaultThreadCurrentCulture屬性介紹://docs.microsoft.com/zh-cn/dotnet/api/system.globalization.cultureinfo.defaultthreadcurrentculture?view=netcore-3.1

在 ASP.NET Core 中使用多個環境://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/environments?view=aspnetcore-3.1

EF Core連接達夢資料庫參考1://blog.csdn.net/lordwish/article/details/104501226

EF Core連接達夢資料庫參考2://blog.csdn.net/lordwish/article/details/108532022