当前位置:网站首页>5. 数据访问 - EntityFramework集成
5. 数据访问 - EntityFramework集成
2022-07-05 18:33:00 【InfoQ】
前言
Masa
EntityFramework
MasaDbContext入门
- 安装.Net 6.0
- 新建ASP.NET Core 空项目
Assignment.MasaEntityFramework
,并安装Masa.Contrib.Data.EntityFrameworkCore
、Swashbuckle.AspNetCore
、Microsoft.EntityFrameworkCore.InMemory
、Microsoft.EntityFrameworkCore.Tools
dotnet 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创建数据库
- 新建类
User
public 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.cs
public class UserDbContext : MasaDbContext
{
public DbSet<User> User { get; set; }
public UserDbContext(MasaDbContextOptions options) : base(options)
{
}
}
> `UserDbContext`改为继承`MasaDbContext`, 并新增一个参数的构造函数,参数类型为`MasaDbContextOptions`
> 当项目中存在多个DbContext时,需要改为继承`MasaDbContext<TDbContext>`,构造函数参数类型改为`MasaDbContext<TDbContext>`
- 新建类
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<TContext>(
this IHost host, Action<TContext, IServiceProvider> seeder) where TContext : DbContext
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<TContext>();
context.Database.EnsureCreated();
seeder(context, services);
}
}
}
- 修改
Program.cs
,新增Swagger
支持
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
Swagger
Postman
- 修改
Program.cs
,添加用户上下文(重点)
builder.Services.AddMasaDbContext<UserDbContext>(options =>
{
options.Builder = (_, dbContextOptionsBuilder) => dbContextOptionsBuilder.UseInMemoryDatabase("test")
});
- 修改
Program.cs
,使项目支持CodeFirst
app.MigrateDbContext<UserDbContext>((context, services) =>
{
});
> 不需要CodeFirst,不支持代码生成数据库可不添加
- 测试
MasaDbContext
,修改Program.cs
app.MapPost("/add", (UserDbContext dbContext, [FromBody] AddUserRequest request) =>
{
dbContext.Set<User>().Add(new User()
{
Name = request.Name,
Gender = request.Gender,
BirthDay = request.BirthDay
});
dbContext.SaveChanges();
});
app.MapGet("/list", (UserDbContext dbContext) =>
{
return dbContext.Set<User>().ToList();
});
> 自行运行项目,执行`add`后创建一个新的用户,之后执行`list`得到一个以上的用户数据,则证明`MasaDbContext`使用无误
如何使用软删除
- 选中
Assignment.MasaEntityFramework
并安装Masa.Contrib.Data.Contracts.EF
dotnet 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<UserDbContext>(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<User>().First(u => u.Id == id);
dbContext.Set<User>().Remove(user);
dbContext.SaveChanges();
});
add
list
delete
list
如何临时禁用软删除过滤
IDataFilter
- 新增
All
方法用于查询所有的数据(包含标记已经删除的数据)
app.MapGet("/all", (UserDbContext dbContext, [FromServices] IDataFilter dataFilter) =>
{
//通过DI获取到IDataFilter,并调用其Disable方法可临时禁用ISoftDelete条件过滤
using (dataFilter.Disable<ISoftDelete>())
{
return dbContext.Set<User>().ToList();
}
});
- 重新运行项目,重复执行验证软删除步骤,确保通过
list
方法访问不到数据
- 重复运行验证软删除步骤的原因在于本示例使用的是内存数据库,项目停止后,所有数据都会被清空,重新执行是为了确保数据存在,仅被标记为删除
- 执行
all
方法,获取所有的数据,查看id所对应的用户数据是否存在
从配置文件中获取数据库连接字符串
- 选中项目
Assignment.MasaEntityFramework
,并安装Masa.Contrib.Data.EntityFrameworkCore.InMemory
dotnet 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<UserDbContext>(options => options.UseInMemoryDatabase().UseFilter());
- 修改
appsettings.json
,增加用户数据库连接字符串:
{
"ConnectionStrings": {
"DefaultConnection": "test"//更换为指定的数据库连接字符串
}
}
- 修改
Program.cs
,新增database
方法,验证当前数据库是test
app.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 DbSet<User> User { get; set; }
public UserDbContext(MasaDbContextOptions options) : base(options)
{
}
}
- 修改配置
appsettings.json
{
"ConnectionStrings": {
"User": "test"//改为从User节点读取数据库连接字符串
}
}
- 除了从配置文件中获取,还支持从其他地方获取数据库连接字符串吗?
Program.cs
appsettings.json
- 修改
Program.cs
builder.Services.Configure<MasaDbConnectionOptions>(option =>
{
option.ConnectionStrings = new ConnectionStrings(new List<KeyValuePair<string, string>>()
{
new("User", "test2")//其中键为节点名,与ConnectionStringName特性的Name值保持一致即可,如果未指定ConnectionStringName,则应该为DefaultConnection,值为数据库连接字符串
});
});
- 修改
appsettings.json
配置
// "ConnectionStrings": {
// "User": "test"
// },
- 调用
database
方法,验证当前数据库是否为test2
IConnectionStringProvider
IDbConnectionStringProvider
- 新建类
CustomizeConnectionStringProvider
public class CustomizeConnectionStringProvider : IConnectionStringProvider
{
public Task<string> GetConnectionStringAsync(string name = "DefaultConnection") => Task.FromResult (GetConnectionString(name));
public string GetConnectionString(string name = "DefaultConnection") => "test3";
}
- 新建类
CustomizeDbConnectionStringProvider
public class CustomizeDbConnectionStringProvider : IDbConnectionStringProvider
{
public List<MasaDbContextConfigurationOptions> DbContextOptionsList { get; } = new()
{
new MasaDbContextConfigurationOptions("test3")
};
}
- 修改
Program.cs
builder.Services.AddSingleton<IConnectionStringProvider,CustomizeConnectionStringProvider>();
builder.Services.AddSingleton<IDbConnectionStringProvider,CustomizeDbConnectionStringProvider>();
- 调用
database
方法,验证当前数据库是否为test3
总结
MasaDbContext
MasaDbContext
本章源码
开源地址
边栏推荐
- Various pits of vs2017 QT
- Is it safe to open an account, register and dig money? Is there any risk? Is it reliable?
- RPC协议详解
- Memory leak of viewpager + recyclerview
- 中文版Postman?功能真心强大!
- Is it safe to open an account and register stocks for stock speculation? Is there any risk? Is it reliable?
- 如何写出好代码 - 防御式编程
- How much does the mlperf list weigh when AI is named?
- jdbc读大量数据导致内存溢出
- Electron installation problems
猜你喜欢
基于can总线的A2L文件解析(3)
彻底理解为什么网络 I/O 会被阻塞?
vs2017 qt的各种坑
About Estimation with Cross-Validation
The main thread anr exception is caused by too many binder development threads
Solutions contents have differences only in line separators
MYSQL中 find_in_set() 函数用法详解
ICML2022 | 长尾识别中分布外检测的部分和非对称对比学习
小程序 修改样式 ( placeholder、checkbox的样式)
蚂蚁集团开源可信隐私计算框架「隐语」:开放、通用
随机推荐
【Autosar 十四 启动流程详解】
文章中的逻辑词
中文版Postman?功能真心强大!
sample_rate(采样率),sample(采样),duration(时长)是什么关系
@Extension、@SPI注解原理
Electron安装问题
让更多港澳青年了解南沙特色文创产品!“南沙麒麟”正式亮相
生词生词生词生词[2]
集合处理的利器
[PM2 details]
Is it safe to make fund fixed investment on access letter?
Memory leak of viewpager + recyclerview
LeetCode 6109. Number of people who know the secret
进程间通信(IPC):共享内存
jdbc读大量数据导致内存溢出
vs2017 qt的各种坑
Lombok @builder annotation
Is it safe to open an account, register and dig money? Is there any risk? Is it reliable?
写作写作写作写作
一文读懂简单查询代价估算