496 lines
17 KiB
C#
496 lines
17 KiB
C#
/***********************************************************
|
||
**项目名称:
|
||
**功能描述: 仓储 的摘要说明
|
||
**作 者: 易栋梁
|
||
**版 本 号: 1.0
|
||
**创建日期: 2015/12/7 16:06:56
|
||
**修改历史:
|
||
************************************************************/
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Linq.Expressions;
|
||
using System.Reflection;
|
||
using System.Threading.Tasks;
|
||
using Microsoft.Extensions.Logging;
|
||
using SqlSugar;
|
||
using Microsoft.AspNetCore.Http;
|
||
using System.Security.Claims;
|
||
using System.Text;
|
||
using NPlatform.Infrastructure.IdGenerators;
|
||
using NPlatform.Filters;
|
||
using System.DirectoryServices;
|
||
using DevExtreme.AspNet.Data;
|
||
|
||
namespace BZPT.Repositories
|
||
{
|
||
/// <summary>
|
||
/// 聚合仓储基类
|
||
/// </summary>
|
||
/// <typeparam name="TEntity">实体类型</typeparam>
|
||
/// <typeparam name="string">主键类型</typeparam>
|
||
public abstract class RepositoryBase<TEntity> : ResultHelper, IRepository<TEntity, string>, IRepositorySugarBase<TEntity, string> where TEntity : EntityBase<string>, new()
|
||
{
|
||
[Autowired]
|
||
public ILogger<RepositoryBase<TEntity>> loggerSvc { get; set; }
|
||
|
||
[Autowired]
|
||
public IHttpContextAccessor httpContextAccessor { get; set; }
|
||
|
||
protected IRepositoryOptions Options;
|
||
|
||
/// <summary>
|
||
/// 数据库连接承载对象,默认注入基础库,管理所有的租户连接。
|
||
/// </summary>
|
||
protected DBContext ContextManage;
|
||
|
||
// 构造函数
|
||
public RepositoryBase(DBContext dbContext)
|
||
{
|
||
ContextManage = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
|
||
}
|
||
|
||
|
||
public string? GetUserId()
|
||
{
|
||
return httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||
}
|
||
|
||
public string? GetUserName()
|
||
{
|
||
return httpContextAccessor.HttpContext?.User?.Identity?.Name;
|
||
}
|
||
|
||
public ISqlSugarClient DbDefault
|
||
{
|
||
get
|
||
{
|
||
return ContextManage;
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 获取业务库对象
|
||
/// </summary>
|
||
public ISqlSugarClient Db
|
||
{
|
||
get
|
||
{
|
||
var tenantId = httpContextAccessor.HttpContext?.User?.Claims?.Where(t => t.Type.ToUpper() =="TENANTID").FirstOrDefault()?.Value;
|
||
|
||
var connection = ContextManage.GetConnection("default");
|
||
if (!string.IsNullOrWhiteSpace(tenantId))
|
||
{
|
||
var tenant = ContextManage.GetConnection("default").Queryable<BZPT.Domains.Entity.Sys.Tenant>().Where(t => t.Id == tenantId).First();
|
||
|
||
var configId = tenantId;//集团ID(也可以叫租户ID)
|
||
if (!ContextManage.IsAnyConnection(configId))
|
||
{ //用非默认ConfigId进行测试
|
||
//添加业务库只在当前上下文有效(原理:SqlSugarScope模式入门文档去看)
|
||
ContextManage.AddConnection(new ConnectionConfig()
|
||
{
|
||
ConfigId = configId,
|
||
ConnectionString = tenant.ConnectionString,
|
||
DbType = Enum.Parse<DbType>(tenant.DbType, true),
|
||
IsAutoCloseConnection = true
|
||
});
|
||
}
|
||
//原理说明
|
||
//IsAnyConnection、AddConnection和GetConnection 都是Scope周期不同请求不会有影响
|
||
connection = ContextManage.GetConnection(configId);
|
||
//可以给业务库result设置AOP和过滤滤器
|
||
}
|
||
|
||
// connection.QueryFilter.AddTableFilter<ILogicDelete>(it => it.IsDeleted == false);
|
||
|
||
|
||
//// 应用过滤器
|
||
//foreach (var ft in this.Options.QueryFilters)
|
||
//{
|
||
// var exp = ft.Value.GetFilter<TEntity>();
|
||
// if (exp != null)
|
||
// {
|
||
// connection.QueryFilter.AddTableFilter<TEntity>(exp);
|
||
// }
|
||
//}
|
||
|
||
return connection;
|
||
}
|
||
}
|
||
|
||
public TEntity this[string key]
|
||
{
|
||
get
|
||
{
|
||
if (EqualityComparer<string>.Default.Equals(key, default(string)))
|
||
{
|
||
return default(TEntity);
|
||
}
|
||
|
||
return this.Db.Queryable<TEntity>().Where(t => t.Id != null && t.Id.Equals(key)).First();
|
||
}
|
||
set
|
||
{
|
||
if (value is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(value));
|
||
}
|
||
|
||
//功能写法可以将插入和更新拆开,然后调用插入和更新独有特性
|
||
var x = Db.Storageable(value).ToStorage();
|
||
var rst = x.AsInsertable.ExecuteCommand();//不存在插入
|
||
var rst2 = x.AsUpdateable.ExecuteCommand();//存在更新
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Initializes a new instance of the <see cref="RepositoryBase{TEntity,string}"/> class.
|
||
/// 仓储基类
|
||
/// </summary>
|
||
/// <param name="option">
|
||
/// 仓储配置
|
||
/// </param>
|
||
public RepositoryBase(IRepositoryOptions option, DBContext dbContext)
|
||
{
|
||
Options = option;
|
||
ContextManage = dbContext;
|
||
}
|
||
|
||
#region 新增、修改、删除
|
||
|
||
/// <summary>
|
||
/// 异步新增
|
||
/// </summary>
|
||
/// <param name="items">新增对象的集合</param>
|
||
/// <returns><placeholder>A <see cref="Task"/> representing the asynchronous operation.</placeholder></returns>
|
||
public async virtual Task<int> AddsAsync(params TEntity[] items)
|
||
{
|
||
if (items is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(items));
|
||
}
|
||
foreach(var item in items)
|
||
{
|
||
if(string.IsNullOrWhiteSpace(item.Id))
|
||
item.Id= StringObjectIdGenerator.Instance.GenerateId().ToString();
|
||
}
|
||
return await this.Db.Insertable<TEntity>(items).ExecuteCommandAsync();
|
||
}
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 异步新增
|
||
/// </summary>
|
||
/// <param name="items">新增对象的集合</param>
|
||
/// <returns><placeholder>A <see cref="Task"/> representing the asynchronous operation.</placeholder></returns>
|
||
public async virtual Task<int> AddOrUpdate(TEntity item)
|
||
{
|
||
if (item is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(item));
|
||
}
|
||
Db.Ado.CommandTimeOut = 30; // 设置30秒超时
|
||
//功能写法可以将插入和更新拆开,然后调用插入和更新独有特性
|
||
var x = Db.Storageable(item).ToStorage();
|
||
var rst = await x.AsInsertable.ExecuteCommandAsync();//不存在插入
|
||
var rst2 = await x.AsUpdateable.ExecuteCommandAsync();//存在更新
|
||
|
||
return rst + rst2;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
public virtual async Task<int> RemoveAsync(Expression<Func<TEntity, bool>> filter)
|
||
{
|
||
if (filter == null) return -1;
|
||
if (typeof(TEntity).IsAssignableFrom(typeof(ILogicDelete)))
|
||
{
|
||
var rst = this.Db.Updateable<TEntity>()
|
||
.SetColumns(t => ((ILogicDelete)t).IsDeleted == true)
|
||
.Where(filter);
|
||
return await rst.ExecuteCommandAsync();
|
||
}
|
||
else
|
||
return await Db.Deleteable<TEntity>().Where(filter).ExecuteCommandAsync();
|
||
}
|
||
|
||
public virtual async Task<int> RemoveAsync(params string[] keys)
|
||
{
|
||
if (keys == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(keys));
|
||
}
|
||
return await this.RemoveAsync(t => keys.Contains(t.Id));
|
||
}
|
||
|
||
public async Task<int> UpdateAsync(TEntity item)
|
||
{
|
||
return await Db.Updateable<TEntity>(item).ExecuteCommandAsync();
|
||
}
|
||
public async Task<int> UpdateAsync(Expression<Func<TEntity, TEntity>> columns, Expression<Func<TEntity, bool>> where)
|
||
{
|
||
return await Db.Updateable<TEntity>()
|
||
.SetColumns(columns)//类只能在表达示里面不能提取
|
||
.Where(where)
|
||
.ExecuteCommandAsync();
|
||
}
|
||
|
||
public async Task<int> UpdatesAsync(List<TEntity> entities, Expression<Func<TEntity, object>> columns)
|
||
{
|
||
return await Db.Updateable(entities)
|
||
.UpdateColumns(columns)
|
||
.ExecuteCommandAsync();
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
#region 查询
|
||
|
||
public async virtual Task<bool> ExistsAsync(string key)
|
||
{
|
||
if (EqualityComparer<string>.Default.Equals(key, default(string)))
|
||
{
|
||
return false;
|
||
}
|
||
return await this.Db.Queryable<TEntity>().AnyAsync(t => t.Id != null && t.Id.Equals(key));
|
||
}
|
||
|
||
public async virtual Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> filter)
|
||
{
|
||
if (filter == null)
|
||
{
|
||
return false;
|
||
}
|
||
//// 应用过滤器
|
||
//foreach (var ft in this.Options.QueryFilters)
|
||
//{
|
||
// var exp = ft.Value.GetFilter<TEntity>();
|
||
// if (exp != null)
|
||
// {
|
||
// filter = filter.AndAlso(exp);
|
||
// }
|
||
//}
|
||
|
||
return await this.Db.Queryable<TEntity>().AnyAsync(filter);
|
||
}
|
||
|
||
public async Task<IEnumerable<TEntity>> GetAllAsync(IEnumerable<SelectSort<TEntity>> sorts = null)
|
||
{
|
||
try
|
||
{
|
||
|
||
// 获取可查询对象
|
||
var query = ContextManage.Queryable<TEntity>();
|
||
// 如果有排序条件,则应用排序
|
||
if (sorts != null && sorts.Any())
|
||
{
|
||
query = query.OrderBy(sorts);
|
||
}
|
||
Type type = typeof(TEntity);
|
||
// 如果实现了ILogicDelete接口且filter不包含IsDeleted条件,则添加IsDeleted=false条件
|
||
if (typeof(ILogicDelete).IsAssignableFrom(type))
|
||
{
|
||
query = query.Where(t => ((ILogicDelete)t).IsDeleted == false);
|
||
}
|
||
// 返回查询结果
|
||
return await query.ToListAsync();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw new Exception("无法从数据库中检索数据.", ex);
|
||
}
|
||
}
|
||
|
||
public async virtual Task<TEntity> FindByAsync(string key)
|
||
{
|
||
if (EqualityComparer<string>.Default.Equals(key, default(string)))
|
||
{
|
||
return default(TEntity);
|
||
}
|
||
|
||
return await this.Db.Queryable<TEntity>().Where(t => t.Id != null && t.Id.Equals(key)).FirstAsync();
|
||
}
|
||
|
||
public async virtual Task<TEntity> GetFirstOrDefaultAsync(Expression<Func<TEntity, bool>> filter)
|
||
{
|
||
if (filter is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(filter));
|
||
}
|
||
return await this.Db.Queryable<TEntity>().Where(filter).FirstAsync();
|
||
|
||
}
|
||
|
||
public async virtual Task<IEnumerable<TEntity>> GetListByExpAsync(Expression<Func<TEntity, bool>> filter, IEnumerable<SelectSort<TEntity>> sorts = null)
|
||
{
|
||
if (filter is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(filter));
|
||
}
|
||
Type type = typeof(TEntity);
|
||
// 如果实现了ILogicDelete接口且filter不包含IsDeleted条件,则添加IsDeleted=false条件
|
||
if (typeof(ILogicDelete).IsAssignableFrom(type))
|
||
{
|
||
if (!filter.ToString().Contains("IsDeleted"))
|
||
{
|
||
// 动态构建 t.IsDeleted == false 条件
|
||
filter = filter.AndAlso(t => ((ILogicDelete)t).IsDeleted == false);
|
||
}
|
||
}
|
||
var setAll = this.Db.Queryable<TEntity>().Where(filter);
|
||
if (sorts != null)
|
||
setAll = setAll.OrderBy(sorts);
|
||
return await setAll.ToListAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// EF 版本,EF实现指定字段查询比较困难,所以先查出所有字段
|
||
/// </summary>
|
||
/// <param name="columnNames"></param>
|
||
/// <param name="filter"></param>
|
||
/// <param name="sorts"></param>
|
||
/// <returns></returns>
|
||
public async virtual Task<IEnumerable<TEntity>> GetListWithColumnsAsync(IEnumerable<string> columnNames, Expression<Func<TEntity, bool>> filter, IEnumerable<SelectSort<TEntity>> sorts = null)
|
||
{
|
||
if (filter is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(filter));
|
||
}
|
||
Type type = typeof(TEntity);
|
||
// 如果实现了ILogicDelete接口且filter不包含IsDeleted条件,则添加IsDeleted=false条件
|
||
if (typeof(ILogicDelete).IsAssignableFrom(type))
|
||
{
|
||
if (!filter.ToString().Contains("IsDeleted"))
|
||
{
|
||
// 动态构建 t.IsDeleted == false 条件
|
||
filter = filter.AndAlso(t => ((ILogicDelete)t).IsDeleted == false);
|
||
}
|
||
}
|
||
var rst = await GetListByExpAsync(filter, sorts);
|
||
return rst;
|
||
}
|
||
|
||
|
||
public async virtual Task<IListResult<TEntity>> GetPagedAsync(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> filter, IEnumerable<SelectSort<TEntity>> sorts)
|
||
{
|
||
if (filter is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(filter));
|
||
}
|
||
RefAsync<int> total = 0;
|
||
|
||
Type type = typeof(TEntity);
|
||
// 如果实现了ILogicDelete接口且filter不包含IsDeleted条件,则添加IsDeleted=false条件
|
||
if (typeof(ILogicDelete).IsAssignableFrom(type))
|
||
{
|
||
if (!filter.ToString().Contains("IsDeleted"))
|
||
{
|
||
// 动态构建 t.IsDeleted == false 条件
|
||
filter = filter.AndAlso(t => ((ILogicDelete)t).IsDeleted == false);
|
||
}
|
||
}
|
||
|
||
var resultSet = this.Db.Queryable<TEntity>().Where(filter);
|
||
if (sorts != null)
|
||
resultSet = resultSet.OrderBy(sorts);
|
||
|
||
var pageData = await resultSet.ToPageListAsync(pageIndex, pageSize, total);
|
||
return base.ListData(pageData, total);
|
||
}
|
||
|
||
|
||
public async virtual Task<IListResult<TEntity>> GetPagedAsync(DataSourceLoadOptions loadOptions)
|
||
{
|
||
var query = this.Db.Queryable<TEntity>();
|
||
|
||
var datas=await query.LoadAsync(loadOptions);
|
||
return datas;
|
||
}
|
||
#endregion
|
||
|
||
#region 统计
|
||
public async Task<int> CountAsync(Expression<Func<TEntity, bool>> filter)
|
||
{
|
||
if (filter is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(filter));
|
||
}
|
||
|
||
return await this.Db.Queryable<TEntity>().CountAsync(filter);
|
||
}
|
||
|
||
public async Task<TValue> MaxAsync<TValue>(Expression<Func<TEntity, TValue>> selector, Expression<Func<TEntity, bool>> filter = null)
|
||
{
|
||
if (selector is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(selector));
|
||
}
|
||
|
||
if (filter is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(filter));
|
||
}
|
||
|
||
return await this.Db.Queryable<TEntity>().Where(filter).MaxAsync(selector);
|
||
}
|
||
|
||
public async Task<TValue> MinAsync<TValue>(Expression<Func<TEntity, TValue>> selector, Expression<Func<TEntity, bool>> filter = null)
|
||
{
|
||
if (selector is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(selector));
|
||
}
|
||
|
||
if (filter is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(filter));
|
||
}
|
||
|
||
return await this.Db.Queryable<TEntity>().Where(filter).MinAsync(selector);
|
||
}
|
||
|
||
public async Task<decimal> SumAsync(Expression<Func<TEntity, decimal>> selector, Expression<Func<TEntity, bool>> filter = null)
|
||
{
|
||
if (selector is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(selector));
|
||
}
|
||
|
||
if (filter is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(filter));
|
||
}
|
||
|
||
return await this.Db.Queryable<TEntity>().Where(filter).SumAsync(selector);
|
||
}
|
||
|
||
public async Task<decimal> AVGAsync(Expression<Func<TEntity, decimal>> selector, Expression<Func<TEntity, bool>> filter = null)
|
||
{
|
||
if (selector is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(selector));
|
||
}
|
||
|
||
if (filter is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(filter));
|
||
}
|
||
|
||
return await this.Db.Queryable<TEntity>().Where(filter).AvgAsync(selector);
|
||
}
|
||
|
||
public Task<int> SaveChangesAsync()
|
||
{
|
||
throw new NotImplementedException("sqlsugar 不支持");
|
||
}
|
||
|
||
#endregion
|
||
|
||
}
|
||
|
||
} |