###### 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 配置更簡單,無需額外容器依賴。讀者可根據需求選擇適用的資料庫。