###### tags: `.NET Core 3.1`, `MySQL`, `MVC`, `Synology`, `Docker` # 在 .NET Core 3.1 應用程式中整合 MySQL 資料庫 `本文由 Grok AI 協助編輯` 本文介紹如何在 .NET Core 3.1 應用程式中整合 MySQL 資料庫,延續前兩篇文章的 `SimpleWeb` 專案,並展示如何擴展功能以連線 MySQL 資料庫。本文假設讀者已熟悉[第一篇](https://hackmd.io/@chihhaolai/dotnetCore31_docker)的部署流程和[第二篇](https://hackmd.io/@chihhaolai/dotnetCore31_oracle)的 Oracle 整合範例。我們將沿用第二篇的「書籍清單」範例,改用 MySQL 作為資料庫,並部署至 Synology NAS 的 Docker 環境。 --- [toc] --- :::info 實驗環境 - **NAS**: RS3614RPxs, DS720P - **DSM**: 6.2.4-25556 Update 2 - **Windows 開發環境**: .NET Core 3.1 SDK, Visual Studio 2019 - **資料庫**: MySQL(版本自定,假設運行於 NAS 或其他主機) ::: --- # 第一部分:應用程式擴展概述 在前兩篇文章中,我們部署了一個基本的 ASP.NET Core 3.1 MVC 應用程式並整合了 Oracle 資料庫。本文將使用相同的「書籍清單」功能: - **書籍管理**:連線 MySQL 資料庫,查詢並展示書籍資料。 此功能將沿用第二篇的模型和視圖,僅更換資料庫為 MySQL。 --- # 第二部分:開發 MySQL 資料庫整合功能 ## 步驟 1:安裝必要的 NuGet 套件 在 `SimpleWeb` 專案中,安裝以下套件: 1. **MySQL 支援**: - 安裝 `MySql.Data.EntityFrameworkCore`(版本與 .NET Core 3.1 相容,例如 8.0.22)。 2. **Entity Framework Core**: - 已安裝於第二篇(`Microsoft.EntityFrameworkCore` 3.1.10),無需重複安裝。 使用命令列: ```bash dotnet add package MySql.Data.EntityFrameworkCore --version 8.0.22 ``` ## 步驟 2:定義模型與資料庫上下文 1. **使用現有模型**: - 沿用第二篇的 `Book.cs`(位於 `Models` 資料夾): ```csharp namespace SimpleWeb.Models { public class Book { public int Id { get; set; } public string Title { get; set; } public string Author { get; set; } } } ``` 2. **建立 `MySqlDbContext`**: - 在 `Data` 資料夾中新增 `MySqlDbContext.cs`: ```csharp using Microsoft.EntityFrameworkCore; using SimpleWeb.Models; namespace SimpleWeb.Data { public class MySqlDbContext : DbContext { public MySqlDbContext(DbContextOptions<MySqlDbContext> options) : base(options) { } public DbSet<Book> Books { get; set; } } } ``` - **用途**:與第二篇的 `OracleDbContext` 類似,`MySqlDbContext` 管理 MySQL 資料庫連線,`DbSet<Book>` 映射到 `BOOKS` 表格。 ## 步驟 3:配置服務與連線字串 1. **編輯 `appsettings.json`**: - 新增 MySQL 連線字串(可保留 Oracle 配置): ```json { "ConnectionStrings": { "MySQL": "Server=<mysql_host>;Database=book_db;User=<user>;Password=<password>", "Oracle": "User Id=<user>;Password=<password>;Data Source=<oracle_host>:<port>/<service_name>" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" } ``` - 替換 `<mysql_host>`、`<user>`、`<password>`,例如:`"Server=192.168.1.200;Database=book_db;User=root;Password=mypass"`。 2. **編輯 `Startup.cs`**: - 註冊 MySQL 上下文: ```csharp using SimpleWeb.Data; using Microsoft.EntityFrameworkCore; public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddDbContext<MySqlDbContext>(options => options.UseMySql(Configuration.GetConnectionString("MySQL"), new MySqlServerVersion(new Version(8, 0, 22)))); services.AddDbContext<OracleDbContext>(options => options.UseOracle(Configuration.GetConnectionString("Oracle"))); } ``` ## 步驟 4:新增控制器與視圖 1. **新增 `BooksController`**: - 在 `Controllers` 資料夾中新增 `BooksController.cs`(與第二篇相同,僅更換上下文): ```csharp using Microsoft.AspNetCore.Mvc; using SimpleWeb.Data; using SimpleWeb.Models; using System.Linq; namespace SimpleWeb.Controllers { public class BooksController : Controller { private readonly MySqlDbContext _mySqlDbContext; public BooksController(MySqlDbContext mySqlDbContext) { _mySqlDbContext = mySqlDbContext; } public IActionResult Index() { var books = _mySqlDbContext.Books.ToList(); return View(books); } [HttpPost] public IActionResult Add(string title, string author) { var book = new Book { Title = title, Author = author }; _mySqlDbContext.Books.Add(book); _mySqlDbContext.SaveChanges(); return RedirectToAction("Index"); } } } ``` - 在 `Views/Books` 資料夾中新增 `Index.cshtml`(與第二篇相同): ```html @model IEnumerable<SimpleWeb.Models.Book> <h2>Book List</h2> <form asp-action="Add" method="post"> <input name="title" placeholder="Book Title" /> <input name="author" placeholder="Author" /> <button type="submit">Add Book</button> </form> <table class="table"> <thead> <tr> <th>ID</th> <th>Title</th> <th>Author</th> </tr> </thead> <tbody> @foreach (var item in Model) { <tr> <td>@item.Id</td> <td>@item.Title</td> <td>@item.Author</td> </tr> } </tbody> </table> ``` ##### 模擬網頁輸出樣子 訪問 `http://<NAS_IP>:62005/Books` 時的模擬輸出(與第二篇一致): ``` Book List [輸入框: Book Title] [輸入框: Author] [Add Book 按鈕] ID | Title | Author ----------------------------------- 1 | The Great Gatsby | F. Scott Fitzgerald 2 | 1984 | George Orwell 3 | To Kill a Mockingbird | Harper Lee (假設剛新增) ``` ##### 當「Add Book」按鈕按下後的程式運作 1. **表單提交**:使用者輸入標題(例如 "To Kill a Mockingbird")和作者(例如 "Harper Lee"),提交 POST 請求至 `/Books/Add`,資料為:`title=To Kill a Mockingbird&author=Harper Lee`。 2. **路由處理**:ASP.NET Core 導向 `BooksController.Add`。 3. **控制器執行**: - `Add` 方法接收 `title` 和 `author`,創建 `Book` 物件。 - `_mySqlDbContext.Books.Add(book)` 標記為待新增。 - `_mySqlDbContext.SaveChanges()` 執行 SQL: ```sql INSERT INTO BOOKS (TITLE, AUTHOR) VALUES ('To Kill a Mockingbird', 'Harper Lee'); ``` - MySQL 自動生成 ID,更新至 `book.Id`。 - 重新導向至 `Index`。 4. **頁面更新**:顯示更新後的書籍清單。 ##### 模型綁定的說明 - **機制**:ASP.NET Core 的模型綁定將表單資料(`title` 和 `author`)映射到 `Add` 方法的參數。表單中 `<input name="title">` 和 `<input name="author">` 的 `name` 屬性必須與參數名稱一致。 - **範例**:若改為 `string titleName, string authorName`,表單需調整為: ```html <input name="titleName" placeholder="Book Title" /> <input name="authorName" placeholder="Author" /> ``` --- # 第三部分:更新 Dockerfile MySQL 不需額外依賴,沿用簡化版 Dockerfile: ```dockerfile FROM mcr.microsoft.com/dotnet/aspnet:3.1 AS base WORKDIR /app EXPOSE 80 # 設置時區 ENV TZ=Asia/Taipei RUN apt-get update && apt-get install -y tzdata RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 預設命令 ENTRYPOINT ["dotnet"] ``` - **說明**:移除第二篇的 `libaio1` 和 `NLS_LANG`,因為 MySQL 不需這些依賴。 ## 重新建構映像 執行 `/volume1/docker/dotnet-runtime/build.sh` 更新映像。 --- # 第四部分:部署流程 ## 步驟 1:初始化 MySQL 資料庫 在 MySQL 上建立表格: ```sql CREATE DATABASE book_db; USE book_db; CREATE TABLE BOOKS ( ID INT AUTO_INCREMENT PRIMARY KEY, TITLE VARCHAR(255), AUTHOR VARCHAR(255) ); ``` - 測試資料(可選): ```sql INSERT INTO BOOKS (TITLE, AUTHOR) VALUES ('The Great Gatsby', 'F. Scott Fitzgerald'); INSERT INTO BOOKS (TITLE, AUTHOR) VALUES ('1984', 'George Orwell'); ``` ## 步驟 2:發佈與部署 - 與第二篇相同,發佈至 `/volume1/docker/mywebapp/`。 ## 步驟 3:配置環境變數(可選) - 在 Docker 容器中新增: - 變數:`ConnectionStrings__MySQL` - 值:`Server=<mysql_host>;Database=book_db;User=<user>;Password=<password>` ## 步驟 4:啟動容器 - 端口 `62005`,卷冊映射至 `/app`,命令為 `dotnet /app/SimpleWeb.dll`。 ## 步驟 5:驗證部署 - 訪問 `http://<NAS_IP>:62005/Books`,新增書籍並確認資料儲存至 MySQL。 --- # 第五部分:修復常見問題 1. **MySQL 連線失敗**: - 檢查連線字串是否正確。 - 確保 MySQL 允許遠端連線。 2. **資料未顯示**: - 確認表格名稱與 `MySqlDbContext` 映射一致。 --- # 結論 本文展示了如何在 .NET Core 3.1 應用程式中整合 MySQL 資料庫,與 Oracle 整合相比,MySQL 配置更簡單,無需額外容器依賴。讀者可根據需求選擇適用的資料庫。