本系列文章打算用一個簡單的案例,展示如何用 Visual Studio 2019 專案範本快速做出一個可以新增修改刪除 SQL 資料的 ASP.NET Core Razor Page 網站,就像傻瓜相機一樣容易上手。(OS: 該不會現在的小朋友已不知傻瓜相機是什麼,結果看不懂比喻)

假想的需求情境像這樣的 - 有個每日伺服器檢查作業(如當兵時連隊裝備一二級保養表那種東西)想要電子化,改成網頁介面供人員登打,待資料結構化後還能玩出發送通知、覆核確認、自動輸出報表... 等花俏應用。然而,所有的一切要從建立清單查詢及新增、修改、刪除資料的網頁介面開始。

每日記錄資料格式如下:

欄位名稱型別欄位說明
IdInt流水序號 (Primary Key)
DateDateTime日期 (設 Unique Index,一天只能有一筆)
StatusVarchar(8)狀態:Normal / Warning / Error
EventSummaryNVarchar(MAX)系統事件彙整
RemarkNVarchar(MAX)補充說明
UserNVarchar(16)彙整人員姓名

這回要來嘗試使用 ASP.NET Core Razor Pages + EF Core,依下列步驟把網站做出來:

  1. 使用 VS2019 Razor Pages 專案範本建立新專案
  2. 資料要用 EF Core 存入 SQL 資料庫,第一步先宣告 Entity 型別 DailyRecord,其屬性如上表
  3. 宣告 JournalDBContext 類別,透過 DbSet<DailyRecord> 屬性將 DailyRecord 納入 EF Core 轄區
  4. 在 Startup 註冊 JournalDBContext,指定連線字串,加上自動建立資料表功能
  5. 利用 Razor Pages 模版自動產生清單及新增修改刪除頁面
  6. 別懷疑,一個可以維護資料庫資料的網站介面這樣就做好了,陽春歸陽春,但絕對堪用
  7. 加入少許客製調整,讓網頁更好用

好,現在就來一步一步實現它。

建立新專案

開啟 Visual Studio 新增 ASP.NET Core Web Application 專案:

範本種類請選第三項 Web Application (說明有 Razor Pages,就是它),圖中(2)指向的 HTTPS 設定,我習慣不啟用,本機測試時可以省點事,上線時如要強制 HTTPS 再改 Code:

Models/DailyRecord.cs

使用 NuGet 加入 Microsoft.EntityFrameworkCore.SqlServer 及 Microsoft.EntityFrameworkCore.Design:

宣告 Models/DailyRecord.cs

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace CRUDExample.Models
{
    /// <summary>
    /// 每日記錄
    /// </summary>
    public class DailyRecord
    {
        /// <summary>
        /// 流水序號
        /// </summary>
        [Key]
        public int Id { get; set; }
        /// <summary>
        /// 日期
        /// </summary>
        public DateTime Date { get; set; } = DateTime.Today;
        /// <summary>
        /// 狀態旗標
        /// </summary>
        [NotMapped]
        public StatusFlags Status { get; set; }
        /// <summary>
        /// 旗標文字
        /// </summary>
        [MaxLength(8)]
        [Column("Status")]
        [Required]
        public string StatusText
        {
            get => Status.ToString();
            set
            {
                StatusFlags tryParseValue;
                if (!Enum.TryParse<StatusFlags>(value, out tryParseValue))
                    throw new ArgumentException($"Invalid StatusText: {value}");
                Status = tryParseValue;
            }
        }
        /// <summary>
        /// 異常或警示事件摘要
        /// </summary>
        [Required]
        public string EventSummary { get; set; }
        /// <summary>
        /// 備註說明
        /// </summary>
        public string Remark { get; set; }
        /// <summary>
        /// 彙整人員姓名
        /// </summary>
        [MaxLength(8)]
        [Required]
        public string User { get; set; }

    }

    /// <summary>
    /// 狀態旗標
    /// </summary>
    public enum StatusFlags
    {
        /// <summary>
        /// 正常
        /// </summary>
        Normal,
        /// <summary>
        /// 警示
        /// </summary>
        Warn,
        /// <summary>
        /// 異常
        /// </summary>
        Error
    }
}

註:Entity 類別設計得花點時間學(但絕對值得,到後面會很有感),若想深入了解可參考先前的系列文章:

宣告 Models/JournalDBContext.cs,加入 DbSet<DailyRecord> 屬性讓 EF Core 將 DailyRecord 列為要對映到資料庫的對象。

using Microsoft.EntityFrameworkCore;

namespace CRUDExample.Models
{
    /// <summary>
    /// 日誌資料
    /// </summary>
    public class JournalDbContext : DbContext
    {
        public DbSet<DailyRecord> Records { get; set; }

        public JournalDbContext(DbContextOptions options) : base(options)
        {

        }

        //REF: https://blog.darkthread.net/blog/ef-core-notes-2/
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //建立日期 Unique Index
            modelBuilder.Entity<DailyRecord>()
                .HasIndex(o => o.Date).IsUnique();
        }
    }
}

準備 SQL LocalDB

我打算用 SQL 當資料庫,開發階段在本機自己跑一份 SQL LocalDB 自己玩最簡便俐落,VS2019 安裝時會預設裝好 SQL LocalDB,故不需要另外安裝 SQL Server 或找測試台資料庫,用 LocalDB 就能測試大部分的 SQL Server 功能,等實際上線時換掉連線字串再改連 SQL Server。

以下簡單介紹使用 Visual Studio Server Explorer 建立 LocalDB 資料庫及取得連線字串的方法:

  1. 開啟 VS2019 Server Explorer,點 [1] Connect To Database,選 [2] Microsoft SQL Server Database File:
  2. Database file name (new or existing) 欄位輸入 .mdf 檔名,檔案還不存在沒關係:

    如果 .mdf 檔還不存在,Visual Studio 會問你要不要新建一個?
  3. LocalDB 的連線字串要怎麼寫?請按第 2 點第一張圖中的 Advanced 鈕,Advanced Properties 視窗的最下方就有完整連線字串:

取得連線字串後,我們要修改 Startup.cs,加入以下設定,註冊 DbContext 並指定使用 SQL Server 儲存資料: (延伸閱讀:不可不知的 ASP.NET Core 依賴注入ASP.NET Core 練習 - 依賴注入 DI)

//... 記得新增以下 Namespace
using Microsoft.EntityFrameworkCore;
using CRUDExample.Models;

public void ConfigureServices(IServiceCollection services)
{
    //註冊 DB Context,指定使用 SQL 資料庫
    services.AddDbContextPool<JournalDbContext>(options =>
    {
        //TODO: 實際應用時連線字串不該寫死,應移入設定檔並加密儲存
        options.UseSqlServer(@"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=X:\Temp\Journal.mdf;Integrated Security=True;Connect Timeout=30");
    });

    services.AddRazorPages();
}

到這一步,EF Core 已認識資料型別 (DailyRecord),並知道我們要用 SQL LocalDB 儲存資料。下一篇接著來見識 EF Core 自動建立資料表的功力。

The tutorial to create a simple CRUD interface using ASP.NET Core Razor Pages + EF Core. The first article is talking about define entity class, DbContext class and choose data provider.


Comments

# by sine

宣告 Models/DailyRecord.cs 請問這一步是新增到哪個檔案底下?謝謝

# by sine

我好像突然懂了wwww

# by sine

不好意思,關於這頁的最後一步的TODO應該怎麼做 //TODO: 實際應用時連線字串不該寫死,應移入設定檔並加密儲存 我查google是這樣做的 string connectionString = ConfigurationManager.ConnectionStrings["MSSQLLocalDB"].ConnectionString; SqlConnection connection = new SqlConnection(connectionString); 但是跳了這個error: System.NullReferenceException: 'Object reference not set to an instance of an object.'

# by Jeffrey

to sine, ConfigurationManager 應該是 ASP.NET 的做法,.NET Core 不適用,參考:https://stackoverflow.com/a/40844342/288936

# by sine

看起來成功了(雖然不知道為什麼w),謝謝 我是參考這一篇 https://blog.darkthread.net/blog/aspnet-core-practice-appsetting/

# by 小郭

今天興高彩烈的想寄信給黑暗執行緒,不過,下面的 mailto 內容根本瞎扯淡,哪裡是信箱了, 黑大,修一修,分點黑暗力量給我吧,還是誰行行好給我黑大的郵件?

# by Jeffrey

to 小郭,可透過 https://www.facebook.com/darkthread.net/ 發訊息,但因時間精力有限,無法有求必應,只能隨喜回覆。

Post a comment