一、仓储
1.使用仓储的好处
2.仓储参考Demo
业务/表仓储
public class BookRepository : IBookRepository, ITransientDependency //接口依赖注入
{
private readonly IFreeSql _fsql;
public BookRepository(IFreeSql fsql)
{
_fsql = fsql;
}
/// <summary>
/// 获取FreeSql
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public IFreeSql GetFreeSql()
{
return _fsql;
}
/// <summary>
/// 分页查询:Book
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
[Route(nameof(GetBookPageListAsync))]
public async Task<IPageList<BookDto>> GetBookPageListAsync(BookSerachInput input)
{
var output = new PageList<BookDto>(new List<BookDto>(), input.PageIndex, input.maxResultCount);
if (false)
{
return output;//不符合要求,返回空数据
}
var fsql = GetFreeSql();
//查表
var queryList = await fsql.Select<Book>()
.Where(x => x.TimePoint.Between(input.StartTime, input.EndTime))
.WhereIf(input.StationCodes.Any(), x => input.StationCodes.Contains(x.CityCode))
.OrderBy(!string.IsNullOrEmpty(input.orderby), input.orderby)
.Page(input.PageIndex, input.maxResultCount)
.Count(out var totalCount)
.ToListAsync();
//映射结果
var dtoList = _objectMapper.Map<List<Book>, List<BookDto>>(queryList);
return new PageList<BookDto>(dtoList, input.PageIndex, input.maxResultCount, totalCount);
}
/// <summary>
/// Book 单一实体 修改
/// </summary>
public async Task<bool> UpdateBookAsync(BookDto input)
{
var fsql = GetFreeSql();
return fsql.Update<BookDto>(input).ExecuteAffrows() != 0;
}
/// <summary>
/// Book 单一实体 保存
/// </summary>
public async Task<bool> SaveBookAsync(BookDto input)
{
var fsql = GetFreeSql();
bool isExist = await fsql.Select<Book>().AnyAsync(x => x.Id == input.Id);//【根据实际修改】根据(联合)主键确定唯一性
if (isExist)
{
return await UpdateBookAsync(input);
}
return await InsertBookAsync(input);
}
/// <summary>
/// Book 单一实体 插入
/// </summary>
public async Task<bool> InsertBookAsync(BookDto input)
{
var fsql = GetFreeSql();
return fsql.Insert(input).ExecuteAffrows() != 0;
}
/// <summary>
/// Book 单一实体 删除
/// </summary>
public async Task<bool> DeleteBookAsync(BookDto input)
{
var fsql = GetFreeSql();
return fsql.Delete<BookDto>(input).ExecuteAffrows() != 0;
}
/// <summary>
/// Book 列表 保存
/// </summary>
public async Task<bool> SaveBookListAsync(List<BookDto> inputList)
{
bool result = true;
var fsql = GetFreeSql();
//获取输入主键
var inputKeyList = inputList.Select(x => x.Id ).Distinct().ToList();
//根据输入主键获取已存在实体
var existList = await fsql.Select<Book>().Where(x => inputKeyList.Contains(x.Id)).ToListAsync();
//获取已存在实体的主键列表
var existKeyList = existList.Select(x => x.Id).Distinct().ToList();
// 获取更新列表和插入列表
var updateList = inputList.Where(x => existKeyList.Contains(x.Id)).ToList();
var insertList = inputList.Where(x => !existKeyList.Contains(x.Id)).ToList();
/*联合主键:
//获取输入主键
var inputKeyList = inputList.Select(x => new { x.Id , x.BookName }).Distinct().ToList();
//根据输入主键获取已存在实体
var existList = await fsql.Select<Book>().Where(x=> inputKeyList.Any(key=>key.Id == x.Id && key.BookName == x.BookName)).ToListAsync();
//获取已存在实体的主键列表
var existKeyList = existList.Select(x => new { x.Id, x.BookName }).Distinct().ToList();
//获取更新列表和插入列表
var updateList = inputList.Where(x => existKeyList.Contains(new { x.Id, x.BookName })).ToList();
var insertList = inputList.Where(x => !existKeyList.Contains(new { x.Id, x.BookName })).ToList();
*/
// 使用批量更新和批量插入方法
bool updateSuccess = await UpdateBookListAsync(updateList); // 批量更新
bool insertSuccess = await InsertBookListAsync(insertList); // 批量插入
return updateSuccess && insertSuccess; // 返回是否全部成功
}
/// <summary>
/// Book 列表 修改
/// </summary>
public async Task<bool> UpdateBookListAsync(List<BookDto> input)
{
var fsql = GetFreeSql();
return fsql.Update<BookDto>(input).ExecuteAffrows() != 0;
}
/// <summary>
/// Book 列表 插入
/// </summary>
public async Task<bool> InsertBookListAsync(List<BookDto> input)
{
var fsql = GetFreeSql();
return fsql.Insert(input).ExecuteAffrows() != 0;
}
/// <summary>
/// Book 列表 删除
/// </summary>
public async Task<bool> DeleteBookListAsync(List<BookDto> input)
{
var fsql = GetFreeSql();
return fsql.Delete<BookDto>(input).ExecuteAffrows() != 0;
}
}
泛型仓储
public class CrudRepository : ICrudRepository,ITransientDependency
{
private readonly IFreeSql _freeSql;
/// <summary>
/// 1.需数据库配置主键、实体特性配置主键和映射列名
/// 2.含单条数据、批量数据实体CRUD
/// </summary>
public CrudRepository(IFreeSql freeSql)
{
_freeSql = freeSql;
}
/// <summary>
/// 获取FreeSql
/// </summary>
public IFreeSql GetFreeSql()
{
var fsql = xxxx;//这里请自行配置
return fsql;
}
public async Task<bool> Insert<T>(T entity) where T : class
{
var fsql = GetFreeSql();
return await fsql.Insert(entity).ExecuteAffrowsAsync() != 0;
}
public async Task<bool> Insert<T>(List<T> enList) where T : class
{
var fsql = GetFreeSql();
return await fsql.Insert(enList).ExecuteAffrowsAsync() != 0;
}
public async Task<bool> Update<T>(T entity) where T : class
{
var fsql = GetFreeSql();
return await fsql.Update<T>().SetSource(entity).ExecuteAffrowsAsync() != 0;
}
public async Task<bool> Update<T>(List<T> enList) where T : class
{
var fsql = GetFreeSql();
return await fsql.Update<T>().SetSource(enList).ExecuteAffrowsAsync() != 0;
}
public async Task<bool> Delete<T>(T entity) where T : class
{
var fsql = GetFreeSql();
return await fsql.Delete<T>(entity).ExecuteAffrowsAsync() != 0;
}
public async Task<bool> Delete<T>(List<T> enList) where T : class
{
var fsql = GetFreeSql();
return await fsql.Delete<T>(enList).ExecuteAffrowsAsync() != 0;
}
public async Task<bool> DeleteByExp<T>(Expression<Func<T, bool>> exp) where T : class
{
var fsql = GetFreeSql();
var effCount = await fsql.Delete<T>().Where(exp).ExecuteAffrowsAsync();
return effCount != 0;
}
public async Task<List<T>> GetList<T>(Expression<Func<T, bool>> exp=null) where T : class
{
var fsql = GetFreeSql();
return await fsql.Select<T>().WhereIf(exp!=null,exp).ToListAsync();
}
public async Task<T> FirstOrDefault<T>(Expression<Func<T, bool>> exp) where T : class
{
var fsql = GetFreeSql();
return await fsql.Select<T>().Where(exp).ToOneAsync();
}
public async Task<bool> Any<T>(Expression<Func<T, bool>> exp) where T : class
{
var fsql = GetFreeSql();
return await fsql.Select<T>().AnyAsync(exp);
}
public async Task<int> Count<T>(Expression<Func<T, bool>> exp) where T : class
{
var fsql = GetFreeSql();
await fsql.Select<T>().Where(exp).Count(out var totals).ToListAsync();
return Convert.ToInt32(totals);
}
/// <summary>
/// 查表返回单列(入参1:字段,入参2:条件)
/// </summary>
/// <returns></returns>
public async Task<List<V>> GetSingleList<T, V>(Expression<Func<T, V>> method1, Expression<Func<T, bool>> method2=null) where T : class
{
var fsql = GetFreeSql();
return await fsql.Select<T>().WhereIf(method2!=null,method2).ToListAsync<V>(method1);
}
/// <summary>
/// 【重载】查表返回单列(V=string),返回的是List<string>()
/// </summary>
/// <returns></returns>
public async Task<List<string>> GetSingleList<T>(Expression<Func<T, string>> method1, Expression<Func<T, bool>> method2=null) where T : class
{
var fsql = GetFreeSql();
return await fsql.Select<T>().WhereIf(method2!=null,method2).ToListAsync<string>(method1);
}
/// <summary>
/// 保存实体
/// (先删后插方案)
/// </summary>
public async Task<bool> Save<T>(T entity) where T : class
{
await Delete(entity);
return await Insert(entity);
}
/// <summary>
/// 保存列表
/// (先删后插方案)
/// </summary>
public async Task<bool> BatchSave<T>(List<T> enlist) where T : class
{
await Delete(enlist);
return await Insert(enlist);
}
}
单例控制台
public class Crud
{
private static IFreeSql _freesql; // 改为静态字段,确保单例
/// <summary>
/// 设置FreeSql实例
/// </summary>
public static void SetFreesql(IFreeSql freesql)
{
_freesql = freesql;
}
/// <summary>
/// 获取FreeSql实例
/// </summary>
public static IFreeSql GetFreeSql()
{
if (_freesql == null)
{
throw new InvalidOperationException("FreeSql instance has not been set.");
}
return _freesql;
}
public static bool Insert<T>(T entity) where T : class
{
var fsql = GetFreeSql();
return fsql.Insert(entity).ExecuteAffrows() != 0;
}
public static bool Insert<T>(List<T> enList) where T : class
{
var fsql = GetFreeSql();
return fsql.Insert(enList).ExecuteAffrows() != 0;
}
public static bool Update<T>(T entity) where T : class
{
var fsql = GetFreeSql();
return fsql.Update<T>().SetSource(entity).ExecuteAffrows() != 0;
}
public static bool Update<T>(List<T> enList) where T : class
{
var fsql = GetFreeSql();
return fsql.Update<T>().SetSource(enList).ExecuteAffrows() != 0;
}
public static bool Delete<T>(T entity) where T : class
{
var fsql = GetFreeSql();
return fsql.Delete<T>(entity).ExecuteAffrows() != 0;
}
public static bool Delete<T>(List<T> enList) where T : class
{
var fsql = GetFreeSql();
return fsql.Delete<T>(enList).ExecuteAffrows() != 0;
}
public static bool DeleteByExp<T>(Expression<Func<T, bool>> exp) where T : class
{
var fsql = GetFreeSql();
var effCount = fsql.Delete<T>().Where(exp).ExecuteAffrows();
return effCount != 0;
}
public static List<T> GetList<T>(Expression<Func<T, bool>> exp = null) where T : class
{
var fsql = GetFreeSql();
return fsql.Select<T>().WhereIf(exp != null, exp).ToList();
}
public static T FirstOrDefault<T>(Expression<Func<T, bool>> exp) where T : class
{
var fsql = GetFreeSql();
return fsql.Select<T>().Where(exp).ToOne();
}
public static bool Any<T>(Expression<Func<T, bool>> exp) where T : class
{
var fsql = GetFreeSql();
return fsql.Select<T>().Any(exp);
}
public static int Count<T>(Expression<Func<T, bool>> exp) where T : class
{
var fsql = GetFreeSql();
var totals = fsql.Select<T>().Where(exp).Count();
return Convert.ToInt32(totals);
}
/// <summary>
/// 查表返回单列(入参1:字段,入参2:条件)
/// </summary>
public static List<V> GetSingleList<T, V>(Expression<Func<T, V>> method1, Expression<Func<T, bool>> method2 = null) where T : class
{
var fsql = GetFreeSql();
return fsql.Select<T>().WhereIf(method2 != null, method2).ToList<V>(method1);
}
/// <summary>
/// 【重载】查表返回单列(V=string),返回的是List<string>()
/// </summary>
public static List<string> GetSingleList<T>(Expression<Func<T, string>> method1, Expression<Func<T, bool>> method2 = null) where T : class
{
var fsql = GetFreeSql();
return fsql.Select<T>().WhereIf(method2 != null, method2).ToList<string>(method1);
}
/// <summary>
/// 保存实体
/// (先删后插方案)
/// </summary>
public static bool Save<T>(T entity) where T : class
{
Delete(entity);
return Insert(entity);
}
/// <summary>
/// 保存列表
/// (先删后插方案)
/// </summary>
public static bool BatchSave<T>(List<T> enlist) where T : class
{
Delete(enlist);
return Insert(enlist);
}
}
二、依赖注入
1.依赖注入的好处
2.什么模块需要用依赖注入
服务、仓储、拦截器、配置服务等
3.【重点】如何进行依赖注入
(1)实现接口
高层服务可以继承ApplicationService,注意高层服务作为接口对外开放需要三要素(请求标签、路由、公开修饰符public),若是仅限本服务使用,则方法可不配置请求标签、路由,用private修饰即可。【本质:继承ApplicationService,相当于实现了ITransientDependency】
public class MyAppService : ApplicationService
{
private readonly IMyService _myService;
public MyAppService(IMyService myService)
{
_myService = myService;
}
//省略方法
}
底层服务可以实现 ITransientDependency,因为底层服务仅涉及业务逻辑(BBL),几乎不需要集成非常多的操作
public class MyService : ITransientDependency , IBookService
{
private readonly IMyService _myService;
public MyService(IMyService myService)
{
_myService = myService;
}
//省略方法
}
(2)特性注入
基本只有底层服务才会这样,因为高层代码继承ApplicationService,是因为该接口自动注入了很多有用的工具。
[Dependency(ServiceLifetime.Transient)]
public class MyService : IBookService
{
private readonly IMyService _myService;
public MyService(IMyService myService)
{
_myService = myService;
}
//省略方法
}
(3)手动注入
在相应的模块类写如下代码:
public class BookStoreApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<BookStoreApplicationModule>();
});
context.Services.AddTransient<IBookService, BookService>(); // 手动注册服务,注意两者是实现和接口的关系
}
}
手动注入我认为的好处是,可以通过配置来轻松替换依赖的实现,这使得你可以在不同的环境(如生产环境、测试环境或开发环境)中使用不同的服务实现。
例如我的邮件服务,有一个是给生产环境用的,一个是给开发环境用的。
public interface IEmailService
{
void SendEmail(string to, string subject, string body);
}
public class SmtpEmailService : IEmailService
{
public void SendEmail(string to, string subject, string body)
{
// 真实的发送邮件逻辑
Console.WriteLine($"Email sent to {to} with subject {subject}");
}
}
public class FakeEmailService : IEmailService
{
public void SendEmail(string to, string subject, string body)
{
// 只是模拟发送邮件,不进行实际操作
Console.WriteLine($"[Fake] Email simulated to {to} with subject {subject}");
}
}
配置模块类,我可以这么写(注意,GetEnvironmentVariable获取的是系统环境变量Key=ASPNETCORE_ENVIRONMENT对应的值,因此,生产环境中只需配置环境变量即可,没有这个环境变量,则读launchSettings.json的内容或者默认为开发环境):
public class MyApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (environment == "Development" || environment == "Production")
{
// 在生产或开发环境中,使用真实的邮件服务
context.Services.AddTransient<IEmailService, SmtpEmailService>();
}
else if (environment == "Test")
{
// 在测试环境中,使用模拟邮件服务
context.Services.AddTransient<IEmailService, FakeEmailService>();
}
}
}
三、三种生命周期
四、高层服务继承ApplicationService的好处
可以直接使用下面自动注入的服务,无需另外注入
1.UnitOfWorkManager
using (var unitOfWork = UnitOfWorkManager.Begin())
{
try
{
// 数据库操作...
await unitOfWork.CompleteAsync(); // 提交事务
}
catch (Exception)
{
await unitOfWork.RollbackAsync(); // 回滚事务
throw; // 重新抛出异常
}
}
2.AsyncExecuter
private readonly IRepository<Student> _student;//除了运用在仓储外,还可以运用在IOrderedEnumerable<T> 中
var list2 = await AsyncExecuter.ToListAsync(_student);//异步操作(等待),必须查完才执行后面代码,不阻塞线程【推荐】
var list3 = _student.ToList();//同步操作,必须查完才执行后面的代码
3.ObjectMapper
// 将实体列表转换为DTO列表
var dtolist = ObjectMapper.Map<List<Book>, List<BookDto>>(entitylist);
4.LoggerFactory
// 使用 LoggerFactory 创建一个 Logger
var logger = LoggerFactory.CreateLogger<MyService>();
logger.LogInformation("xxxxxxxxxxx");
5.CurrentTenant
// 获取当前租户信息
var tenantId = CurrentTenant.GetId();
6.CurrentUser
// 获取当前用户ID
var userId = CurrentUser.UserId;
7.GuidGenerator
var guidId = GuidGenerator.Create();//生成Guid(ABP框架经过优化可以产生连续的GUID.这对于关系数据库中的聚集索引非常重要.)
8.也顺带继承了ITransientDependency,底层服务继承它可以完成依赖注入,避免出现找不到服务的问题
我认为比较重要的好处:
继承ApplicationService = IAvoidDuplicateCrossCuttingConcerns(日志记录) + IValidationEnabled(接口输入验证)+IUnitOfWorkEnabled(事务)+ IAuditingEnabled(审计)+IGlobalFeatureCheckingEnabled(特性检查)+ ITransientDependency(依赖注入)
(1)继承了ApplicationService,可用映射 ObjectMapper.Map
(2)继承了ITransientDependency,保证了服务被正确注入到依赖容器,高层代码才能调用这个底层代码。