ASP.NET Core 使用 Entity Framework Core 存取 MySql/MariaDb 資料庫步驟(資料庫優先)

本篇使用 MariaDb 做示範,和 MySql 是同樣的做法,如果是 SqlServer 可以看這篇

範例資料表

在資料庫中建立了用來當作範例的員工資料表:
    
create table employees
(
    id   int auto_increment,
    code varchar(10)  not null,
    name nvarchar(50) not null,
    constraint employees_pk
        primary key (id)
);
    

範例資料:
    
INSERT INTO employees (Code, Name) VALUES (N'A01', N'小明');
INSERT INTO employees (Code, Name) VALUES (N'A02', N'大頭');
    

安裝套件

依照資料庫種類安裝對應的 EntityFrameworkCore 套件,這裡示範的是 MySql 和 MariaDb 通用的套件:
	
dotnet add package Pomelo.EntityFrameworkCore.MySql
    

註: 在筆者撰文的當下 Pomelo.EntityFrameworkCore.MySql 對應 Entity Framework Core 8 的套件還在 beta 版本,如果使用 Entity Framework Core 8 需要安裝版號 8.0.0 或以上,目前最新版為 8.0.0-beta.2 ,在安裝時直接加上 --version 8.0.0-beta.2 即可指定版本。

我們使用的是資料庫優先,就是已經建立好資料庫了,使用指令依照資料庫的資料表、欄位在 C# 中自動建立對應的 Entity ,需要再額外安裝 Design 的套件:
	
dotnet add package Microsoft.EntityFrameworkCore.Design
    

建立連接字串

需要連接到資料庫,程式會需要知道連接的資訊,為了避免安全問題和不容易修改,我們將連接資訊記錄在設定檔 appsettings.json 中
    
{
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DefaultConnection": "server=localhost;port=3306;database=my_database;user=my_user;password=my_password;"
  }
}
    

註: 記得替換 ip, port, 資料庫名稱、登入使用者、密碼

同步實體

使用指令使用設定檔中的連接字串依照資料庫建立對應實體,詳細指令使用方式可以查看延伸閱讀:
    
dotnet ef dbcontext scaffold Name=ConnectionStrings:DefaultConnection Pomelo.EntityFrameworkCore.MySql -d --context-dir Data/Contexts --context ApplicationDbContext -o Data/Entities -f
    

完成後會在 Entity 資料夾中產生 Table 和 View 對應的實體,並且在 Contexts 資料夾中會產生 ApplicationDbContext.cs ,之後我們都會使用 ApplicationDbContext 來操作資料庫。
延伸閱讀: 利用 dotnet ef 指令依據資料庫定義產生 Entity Framework Core 資料庫實體定義程式碼

依賴注入容器註冊

在 Program.cs 中加入以下程式碼,註冊 ApplicationDbContext,和 SQL Server 不同的是 MySql 和 Mariadb 需要紀錄版本號碼。
MariaDb 的設定如下:
    
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var serverVersion = new MariaDbServerVersion(new Version(10, 6, 12));

builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseMySql(connectionString, serverVersion)
    .LogTo(Console.WriteLine, LogLevel.Information) // DbContext 操作紀錄
    .EnableSensitiveDataLogging() // 敏感資料紀錄
    .EnableDetailedErrors() // 詳細錯誤紀錄
);

var app = builder.Build();

    

MySql 的版本:
    
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var serverVersion = new MySqlServerVersion(new Version(8, 0, 36));

builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseMySql(connectionString, serverVersion)
    .LogTo(Console.WriteLine, LogLevel.Information) // DbContext 操作紀錄
    .EnableSensitiveDataLogging() // 敏感資料紀錄
    .EnableDetailedErrors() // 詳細錯誤紀錄
);

var app = builder.Build();
    

如果不需要 Log 輸出紀錄的話可以將上面的 6 ~ 8 行移除。

使用範例

我們建立一個 EmployeeController ,用來示範 新增、修改、刪除、查詢 功能:
    
using Microsoft.AspNetCore.Mvc;
using WebApplication20231226.Data.Contexts;
using WebApplication20231226.Data.Entities;

namespace QuickPaste.Controllers;

[ApiController]
[Route("[controller]")]
public class EmployeeController : ControllerBase
{
    private readonly ApplicationDbContext _context;

    public EmployeeController(ApplicationDbContext context)
    {
        _context = context;
    }

    [HttpGet]
    public ActionResult Get()
    {
        var employees = _context.Employees.ToList();
        return Ok(employees);
    }

    public record EmployeeDto(string Code, string Name);

    [HttpPost]
    public ActionResult Post(EmployeeDto dto)
    {
        var employee = new Employee
        {
            Code = dto.Code,
            Name = dto.Name
        };
        _context.Employees.Add(employee);
        _context.SaveChanges();
        return StatusCode(201);
    }

    [HttpPut("{id}")]
    public ActionResult Put(string id, EmployeeDto dto)
    {
        var employee = _context.Employees.FirstOrDefault(x => x.Id.ToString() == id);
        if (employee == null) return NotFound();

        employee.Code = dto.Code;
        employee.Name = dto.Name;
        _context.SaveChanges();
        return Ok();
    }

    [HttpDelete("{id}")]
    public ActionResult Delete(string id)
    {
        var employee = _context.Employees.FirstOrDefault(x => x.Id.ToString() == id);
        if (employee == null) return NotFound();

        _context.Employees.Remove(employee);
        _context.SaveChanges();
        return Ok();
    }
}
    

留言