一、充血模型
- 依赖注入在ORM中的应用主要是充血模型
- DBShadow是基于ShadowSql和PocoEmit开发而来的
- DBShadow从PocoEmit继承了依赖注入的功能
- PocoEmit依赖注入请查看文章PocoEmit遥遥领先于AutoMapper之打通充血模型的任督二脉
二、来个Case演示一下DBShadow注入
1. 充血模型代码
- 为了方便修改AccountModify增加了方法ModifyAsync
- 为了实现AccountModify方法注入了AccountModifyService
- 这就是个典型充血模型
csharp
/// <summary>
/// 账户修改
/// </summary>
/// <param name="service"></param>
public class AccountModify(AccountModifyService<Account> service)
: Account
{
private readonly AccountModifyService<Account> _service = service;
/// <summary>
/// 账户修改
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public Task ModifyAsync(long amount, CancellationToken token = default)
{
Amount = amount;
return _service.ModifyAsync(this, token);
}
}
2. 服务初始化
- mapper既支持预编译也支持依赖注入,两者必须用同一个mapper
- AccountGetService是泛型服务,它可以支持普通模型也支持充血模型
- _accountService获取普通模型对象
- _accountService2获取充血模型对象
csharp
private static readonly IMapper _mapper = Mapper.Create();
private static readonly IShadowBuilder _builder = ShadowBuilder.CreateCache(_mapper, _engine, _dataSource);
private static readonly AccountTable _table = new();
private static readonly AccountModifyService<Account> _modifyService = new(_table, _builder);
private static readonly AccountGetService<long, Account> _accountService = new(_table, _builder);
private static readonly AccountGetService<long, AccountModify> _accountService2 = new(_table, _builder);
3. "注册服务"
- UseDefault是PocoEmit一种简化的注入机制
- PocoEmit处理属性和构造函数参数缺失映射规则时会从UseDefault的配置中查找
csharp
_mapper.UseDefault(_modifyService);
4. 依赖注入演示代码
- _accountService2获取充血模型,余额为1000
- 使用充血模型的方法ModifyAsync把余额修改为500
- 使用_accountService获取普通模型对象,确认余额已经是500了
- 充血模型和普通模型是使用相同类获取的,都成功了
- 最重要的是AccountModify能正常工作,说明AccountModify的service注入成功
csharp
var accountModify = await _accountService2.GetAsync(1L);
Assert.NotNull(accountModify);
Assert.Equal(1000L, accountModify.Amount);
await accountModify.ModifyAsync(500L);
var account = await _accountService.GetAsync(1L);
Assert.NotNull(account);
Assert.Equal(1L, account.Id);
Assert.Equal(500L, account.Amount);
三、用IOC注入
- PocoEmit支持IOC注入
- DBShadow自然也继承了IOC注入功能
- 下面Case演示一下IOC注入
1. IOC注册代码
- 其中UseSingleton是告知PocoEmit从IOC容器获取服务用来注入
- 详情查看文章PocoEmit遥遥领先于AutoMapper之打通充血模型的任督二脉
- 另外服务都是注册成单例,这点与EF要区别开,基于EF的服务一般都需要注册为Scope
- 因为DBShadow是线程安全的架构,对异步、多线程友好
- 当然定义为非单例的也能正常运行
csharp
var mapper = Mapper.Default;
IShadowBuilder builder = ShadowBuilder.CreateCache(mapper, _engine, _dataSource);
var services = new ServiceCollection()
.AddSingleton(mapper)
.AddSingleton(builder)
.AddSingleton<AccountTable>()
.AddSingleton(typeof(AccountCreateService<>))
.AddSingleton(typeof(AccountModifyService<>))
.AddSingleton(typeof(AccountGetService<,>));
var serviceProvider = services.BuildServiceProvider();
mapper.UseSingleton(serviceProvider);
2. 演示代码
- 执行代码与前面的Case基本一致
- 说明DBShadow与PocoEmit完美对接上了
- 也可以说DBShadow与IOC容器也完美对接上了
csharp
var accountService = serviceProvider.GetRequiredService<AccountGetService<long, Account>>();
var accountService2 = serviceProvider.GetRequiredService<AccountGetService<long, AccountModify>>();
var accountModify = await accountService2.GetAsync(1L);
Assert.NotNull(accountModify);
Assert.Equal(1000L, accountModify.Amount);
await accountModify.ModifyAsync(500L);
var account = await accountService.GetAsync(1L);
Assert.NotNull(account);
Assert.Equal(500L, account.Amount);
四、总结
- DBShadow继承了PocoEmit的依赖注入功能
- 充血模型是一种OOP的开发方式,可以增加代码可读性
- DBShadow能有效简化充血模型的使用
- DBShadow是线程安全的架构,适合异步、多线程、高并发和微服务的场景
- 本文Case来源DBShadow项目的单元测试,可以查阅源码
源码托管地址: https://github.com/donetsoftwork/DBShadow.net ,欢迎大家直接查看源码。
gitee同步更新:https://gitee.com/donetsoftwork/DBShadow.net
如果大家喜欢请动动您发财的小手手帮忙点一下Star,谢谢!!!