数据访问 - EntityFramework集成
前言
Masa提供了基于EntityFramework的数据集成,并提供了数据过滤与软删除的功能,下面我们将介绍如何使用它?
MasaDbContext入门
- 安装.Net 6.0
-
新建ASP.NET Core 空项目
Assignment.MasaEntityFramework,并安装Masa.Contrib.Data.EntityFrameworkCore、Swashbuckle.AspNetCore、Microsoft.EntityFrameworkCore.InMemory、Microsoft.EntityFrameworkCore.Toolsdotnet add package Masa.Contrib.Data.EntityFrameworkCore --version 0.4.0-rc.4 dotnet add package Swashbuckle.AspNetCore --version 6.2.3 dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 6.0.5 dotnet add package Microsoft.EntityFrameworkCore.Tools --version 6.0.5安装
Swashbuckle.AspNetCore是为了方便通过Swagger来操作服务
安装Microsoft.EntityFrameworkCore.InMemory是为了方便,因此使用内存数据库,如果需要使用其他数据库,请自行安装对应的包
安装Microsoft.EntityFrameworkCore.Tools是为了使用CodeFirst创建数据库 -
新建类
Userpublic class User { public int Id { get; set; } public string Name { get; set; } public uint Gender { get; set; } public DateTime BirthDay { get; set; } public DateTime CreationTime { get; set; } public User() { this.CreationTime = DateTime.Now; } } -
新建用户上下文
UserDbContext.cspublic class UserDbContext : MasaDbContext { public DbSetUser { get; set; } public UserDbContext(MasaDbContextOptions options) : base(options) { } } UserDbContext改为继承MasaDbContext, 并新增一个参数的构造函数,参数类型为MasaDbContextOptions
当项目中存在多个DbContext时,需要改为继承MasaDbContext,构造函数参数类型改为MasaDbContext -
新建类
AddUserRequest作为添加用户的参数public class AddUserRequest { public string Name { get; set; } public uint Gender { get; set; } public DateTime BirthDay { get; set; } } -
新建类
HostExtensions用于迁移数据库(使用CodeFirst)public static class HostExtensions { public static void MigrateDbContext( this IHost host, Action seeder) where TContext : DbContext { using (var scope = host.Services.CreateScope()) { var services = scope.ServiceProvider; var context = services.GetRequiredService (); context.Database.EnsureCreated(); seeder(context, services); } } } -
修改
Program.cs,新增Swagger支持builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); app.UseSwagger(); app.UseSwaggerUI();
不需要
Swagger可不添加,使用Swagger仅仅是为了测试调用服务,使用Postman或其他的Http工具也可以
-
修改
Program.cs,添加用户上下文(重点)builder.Services.AddMasaDbContext(options => { options.Builder = (_, dbContextOptionsBuilder) => dbContextOptionsBuilder.UseInMemoryDatabase("test") }); -
修改
Program.cs,使项目支持CodeFirstapp.MigrateDbContext((context, services) => { }); 不需要CodeFirst,不支持代码生成数据库可不添加
-
测试
MasaDbContext,修改Program.csapp.MapPost("/add", (UserDbContext dbContext, [FromBody] AddUserRequest request) => { dbContext.Set().Add(new User() { Name = request.Name, Gender = request.Gender, BirthDay = request.BirthDay }); dbContext.SaveChanges(); }); app.MapGet("/list", (UserDbContext dbContext) => { return dbContext.Set ().ToList(); }); 自行运行项目,执行
add后创建一个新的用户,之后执行list得到一个以上的用户数据,则证明MasaDbContext使用无误
如何使用软删除
-
选中
Assignment.MasaEntityFramework并安装Masa.Contrib.Data.Contracts.EFdotnet add package Masa.Contrib.Data.Contracts.EF --version 0.4.0-rc.4 -
修改类
User,并实现ISoftDelete,代码改为:public class User : ISoftDelete//重点:改为实现ISoftDelete { public int Id { get; set; } public string Name { get; set; } public uint Gender { get; set; } public DateTime BirthDay { get; set; } public DateTime CreationTime { get; set; } public bool IsDeleted { get; private set; } public User() { this.CreationTime = DateTime.Now; } }增加实现
ISoftDelete,并为IsDeleted属性添加set支持(可以是private set;) -
修改
Program.cs,并启用数据过滤builder.Services.AddMasaDbContext(options => { options.Builder = (_, dbContextOptionsBuilder) => dbContextOptionsBuilder.UseInMemoryDatabase("test"); options.UseFilter();//启用数据过滤,完整写法:options.UseFilter(filterOptions => filterOptions.EnableSoftDelete = true); }); -
测试软删除是否成功
-
修改
Program.cs,新增删除方法app.MapDelete("/delete", (UserDbContext dbContext, int id) => { var user = dbContext.Set().First(u => u.Id == id); dbContext.Set ().Remove(user); dbContext.SaveChanges(); });
最后,先调用add方法创建用户后,之后再调用list方法获取所有的用户列表,并取出任意一条id信息,然后再调用delete方法删除用户,最后再调用list方法,查看取出的id是否存在,以此来验证软删除是否有效。
如何临时禁用软删除过滤
默认查询中会将标记已经被删除的数据过滤不再进行查询,但也有一些场景需要查询所有的数据,此时就需要用到数据过滤IDataFilter
-
新增
All方法用于查询所有的数据(包含标记已经删除的数据)app.MapGet("/all", (UserDbContext dbContext, [FromServices] IDataFilter dataFilter) => { //通过DI获取到IDataFilter,并调用其Disable方法可临时禁用ISoftDelete条件过滤 using (dataFilter.Disable()) { return dbContext.Set ().ToList(); } }); -
重新运行项目,重复执行验证软删除步骤,确保通过
list方法访问不到数据重复运行验证软删除步骤的原因在于本示例使用的是内存数据库,项目停止后,所有数据都会被清空,重新执行是为了确保数据存在,仅被标记为删除
-
执行
all方法,获取所有的数据,查看id所对应的用户数据是否存在
从配置文件中获取数据库连接字符串
-
选中项目
Assignment.MasaEntityFramework,并安装Masa.Contrib.Data.EntityFrameworkCore.InMemorydotnet add package Masa.Contrib.Data.EntityFrameworkCore.InMemory --version 0.4.0-rc.4根据需要安装对应数据库包即可,如:
Masa.Contrib.Data.EntityFrameworkCore.SqlServer(SqlServer)、Masa.Contrib.Data.EntityFrameworkCore.Pomelo.MySql(Pomelo提供的MySql)、Masa.Contrib.Data.EntityFrameworkCore.Oracle(Oracle)等 -
修改
Program.cs,调整添加用户上下文配置为:builder.Services.AddMasaDbContext(options => options.UseInMemoryDatabase().UseFilter()); -
修改
appsettings.json,增加用户数据库连接字符串:{ "ConnectionStrings": { "DefaultConnection": "test"//更换为指定的数据库连接字符串 } } -
修改
Program.cs,新增database方法,验证当前数据库是testapp.MapGet("/database", (UserDbContext dbContext) => { var field = typeof(MasaDbContext).GetField("Options", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)!; var masaDbContextOptions = field.GetValue(dbContext) as MasaDbContextOptions; foreach (var dbContextOptionsExtension in masaDbContextOptions!.Extensions) { if (dbContextOptionsExtension is InMemoryOptionsExtension memoryOptionsExtension) { return memoryOptionsExtension.StoreName; } } return ""; });
最后访问http://localhost:5002/database,验证当前的数据库名称与修改后的数据库名称是否一致

常见问题
- 如何更改默认读取的配置节点?
-
修改用户上下文
UserDbContext并增加ConnectionStringName特性:[ConnectionStringName("User")]//自定义节点名 public class UserDbContext : MasaDbContext { public DbSetUser { get; set; } public UserDbContext(MasaDbContextOptions options) : base(options) { } } -
修改配置
appsettings.json{ "ConnectionStrings": { "User": "test"//改为从User节点读取数据库连接字符串 } }
- 除了从配置文件中获取,还支持从其他地方获取数据库连接字符串吗?
目前有两种办法可以更改数据库连接字符串。
方法1: 修改Program.cs,并删除appsettings.json数据库连接字符串的配置
-
修改
Program.csbuilder.Services.Configure(option => { option.ConnectionStrings = new ConnectionStrings(new List >() { new("User", "test2")//其中键为节点名,与ConnectionStringName特性的Name值保持一致即可,如果未指定ConnectionStringName,则应该为DefaultConnection,值为数据库连接字符串 }); }); -
修改
appsettings.json配置// "ConnectionStrings": { // "User": "test" // }, -
调用
database方法,验证当前数据库是否为test2

方法2: 重写IConnectionStringProvider和IDbConnectionStringProvider的实现并添加到DI中
-
新建类
CustomizeConnectionStringProviderpublic class CustomizeConnectionStringProvider : IConnectionStringProvider { public TaskGetConnectionStringAsync(string name = "DefaultConnection") => Task.FromResult (GetConnectionString(name)); public string GetConnectionString(string name = "DefaultConnection") => "test3"; } -
新建类
CustomizeDbConnectionStringProviderpublic class CustomizeDbConnectionStringProvider : IDbConnectionStringProvider { public ListDbContextOptionsList { get; } = new() { new MasaDbContextConfigurationOptions("test3") }; } -
修改
Program.csbuilder.Services.AddSingleton(); builder.Services.AddSingleton (); -
调用
database方法,验证当前数据库是否为test3

总结
本篇文章主要讲解了MasaDbContext的基本用法以及软删除、数据过滤如何使用,下篇文章我们会讲解一下MasaDbContext是如何实现软删除、数据过滤的,以及本篇文章中提到使用数据库时不指定数据库链接字符串时如何实现的
本章源码
Assignment05
https://github.com/zhenlei520/MasaFramework.Practice
开源地址
MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks
MASA.Contrib:https://github.com/masastack/MASA.Contrib
MASA.Utils:https://github.com/masastack/MASA.Utils
MASA.EShop:https://github.com/masalabs/MASA.EShop
MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor
如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们
