EFCore框架相关的内容可以参考笔记库的软件工程/dotNet/EFCore
相关章节。这篇笔记我们介绍如何在ASP.NET Core工程中使用EFCore操作数据库表。
我们这里使用.NET6版本和MySQL数据库,执行命令安装以下NuGet依赖项。
dotnet add package Microsoft.EntityFrameworkCore --version 6.0.36
dotnet add package Microsoft.EntityFrameworkCore.Tools --version 6.0.36
dotnet add package Pomelo.EntityFrameworkCore.MySql --version 6.0.3
操作数据迁移时需要执行EFCore的命令行工具,这需要用到dotnet ef
命令,如果我们尚未安装该命令行工具,可以执行以下命令安装。
dotnet tool install --global dotnet-ef --version 6.0.36
下面代码我们创建了DbContext和自定义的数据模型Student
。
using Microsoft.EntityFrameworkCore;
namespace DemoWebAPI.Model;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 从程序集中引入所有数据表映射配置类
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
base.OnModelCreating(modelBuilder);
}
}
namespace DemoWebAPI.Model;
public class Student
{
public long Id { get; set; }
public string Name { get; set; }
public int? Age { get; set; }
public DateTime CreateTime { get; set; }
}
对于数据模型,我们采用FluentAPI进行配置。
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace DemoWebAPI.Model;
public class StudentEntityConfig : IEntityTypeConfiguration<Student>
{
public void Configure(EntityTypeBuilder<Student> builder)
{
builder.ToTable("t_student");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id).ValueGeneratedOnAdd().HasColumnName("id");
builder.Property(x => x.Name).IsRequired().HasMaxLength(50).HasColumnName("name");
builder.Property(x => x.Age).HasColumnName("age");
builder.Property(x => x.CreateTime).IsRequired().HasColumnName("create_time");
}
}
在Program.cs
中,我们需要调用builder.Services.AddDbContext()
方法注册EFCore需要使用的DbContext
。
// 集成EFCore相关服务
builder.Services.AddDbContext<AppDbContext>(options =>
{
const string connStr = "Server=localhost;Port=3306;Database=netstore;User=root;Password=root;";
options.UseMySql(connStr, ServerVersion.AutoDetect(connStr));
});
代码中,我们指定了MySQL数据库服务器的连接串,出于节省篇幅考虑这里我们是将连接串直接写在代码里的,实际开发中建议配置在appsettings.json
内并通过配置框架读取。
如上配置好数据模型、DbContext并注册到ASP.NET Core后,我们就可以创建并执行数据迁移了,我们可以执行以下命令进行操作。
dotnet ef migrations add InitialCreate
dotnet ef database update
数据迁移执行后,我们可以查看数据库中的表结构,如果一切正常,我们可以看到自动创建的__EFMigrationsHistory
和我们数据模型对应的t_student
。
下面我们写一个简单的查询接口来演示EFCore在ASP.NET Core中的使用,我们这里将程序划分为控制器层和业务逻辑层两个部分,StudentController
调用StudentService
,具体操作数据实体类的代码在业务逻辑层执行。
StudentController.cs
using DemoWebAPI.Model;
using DemoWebAPI.Services;
using Microsoft.AspNetCore.Mvc;
namespace DemoWebAPI.Controllers;
[ApiController]
[Route("api/[controller]")]
public class StudentController : ControllerBase
{
private readonly StudentService _studentService;
public StudentController(StudentService studentService)
{
_studentService = studentService;
}
[HttpGet("[action]")]
public ActionResult<ApiResult> GetStudentById([FromQuery] long id)
{
Student? student = _studentService.QueryStudentById(id);
return ApiResult.Success(student);
}
}
Program.cs
// 注册StudentService服务
builder.Services.AddScoped<StudentService>();
StudentService.cs
using DemoWebAPI.Model;
namespace DemoWebAPI.Services;
public class StudentService
{
private AppDbContext _dbContext;
public StudentService(AppDbContext dbContext)
{
_dbContext = dbContext;
}
public Student? QueryStudentById(long id)
{
return _dbContext.Students.SingleOrDefault(s => s.Id == id);
}
}
代码中,我们将AppDbContext
通过依赖注入的方式注入到了StudentService
中,QueryStudentById()
方法接收一个GET参数作为查询条件,最终我们调用EFCore筛选指定主键的值。
在ASP.NET Core中,我们可以使用TransactionScope
来管理事务,确保数据库操作要么全部成功要么全部失败,这保证了数据的一致性和完整性,常用于涉及多个数据库操作并需要保证原子性的场景。
using DemoWebAPI.Model;
using System.Transactions;
namespace DemoWebAPI.Services;
public class StudentService
{
private AppDbContext _dbContext;
public StudentService(AppDbContext dbContext)
{
_dbContext = dbContext;
}
public void DemoTransaction()
{
using TransactionScope scope = new TransactionScope(TransactionScopeOption.Required);
// 操作1
Student s1 = new()
{
Name = "汤姆",
Age = 18,
CreateTime = DateTime.Now
};
_dbContext.Students.Add(s1);
_dbContext.SaveChanges();
// 操作2
Student s2 = new()
{
Name = "杰瑞",
Age = 20,
CreateTime = DateTime.Now
};
_dbContext.Students.Add(s2);
_dbContext.SaveChanges();
scope.Complete();
}
}
代码中,我们在DemoTransaction()
方法中启用了TransactionScope
,如果事务操作完成,我们需要手动调用scope.Complete()
告知提交事务,如果中间的操作中有某一步出错了,没有手动调用scope.Complete()
时它就会自动回滚。
TransactionScopeOption.Required
指定了当发生嵌套事务时的行为:
Required
:如果存在外部事务,则加入外部事务;否则,创建一个新事务。大多数情况下使用这个选项。RequiresNew
:总是创建一个新事务,即使存在外部事务。Suppress
:不参与任何事务,当前操作会在没有事务的情况下执行。