/// <summary>/// 实体基类/// </summary>public class EntityBase{/// <summary>/// ID/// </summary>[Key][Required][MaxLength(20)][JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public string id { get; set; } = SnowFlake.GenId().ToString();/// <summary>/// 创建时间/// </summary>[Required][JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public DateTime createTime { get; set; } = DateTime.Now;/// <summary>/// 创建人ID/// </summary>public string createUserId { get; set; }/// <summary>/// 创建人名称/// </summary>public string createUserName { get; set; }/// <summary>/// 修改时间/// </summary>[Required][JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public DateTime modifiedTime { get; set; } = DateTime.Now;/// <summary>/// 修改人/// </summary>public string modefiedUserId { get; set; }/// <summary>/// 修改人名称/// </summary>public string modifiedUserName { get; set; }/// <summary>/// 是否已删除/// </summary>[Required][JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public bool isDeleted { get; set; } = false;}
public class BllBase : IDisposable{/// <summary>////// </summary>public bool IsTopBll = true;/// <summary>////// </summary>public SqliteContext SqlLiteDbContext { get; set; }/// <summary>////// </summary>public MySqlContext MySqlDbContext { get; set; }/// <summary>////// </summary>public InfluxDBClient InfluxClient { get; set; }/// <summary>////// </summary>public List<IDisposable> DalList { get; set; } = new List<IDisposable>();/// <summary>////// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public T CreateDal<T>() where T : DalBase, new(){var dal = new T();if (dal is SqlLiteDalBase sqlLiteDalBase){SqlLiteDbContext ??= new SqliteContext();sqlLiteDalBase.DbContext = SqlLiteDbContext;}else if (dal is MySqlDalBase sqlDalBase){MySqlDbContext ??= new MySqlContext();sqlDalBase.DbContext = MySqlDbContext;}else if (dal is InfluxDbDalBase influxDbDalBase){InfluxClient ??= new InfluxDBClient(SystemConfigReader.influxlDb, SystemConfigReader.influxlDbUsername,SystemConfigReader.influxlDbPWD);influxDbDalBase.InfluxClient = InfluxClient;}DalList.Add(dal);return dal;}/// <summary>////// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public DalWithTransaction<T> CreateDalWithTransaction<T>() where T : MySqlDalBase, new(){DalWithTransaction<T> res = new DalWithTransaction<T>();var dal = CreateDal<T>();res.Dal = dal;res.Transaction = MySqlDbContext.Database.BeginTransaction();return res;}/// <summary>////// </summary>/// <returns></returns>public IDbContextTransaction BeginMysqlTransaction(){return MySqlDbContext.Database.BeginTransaction();}//*************************************************************/// <summary>////// </summary>/// <param name="entity"></param>/// <typeparam name="TO"></typeparam>/// <typeparam name="TFrom"></typeparam>/// <returns></returns>protected TO ConvertData<TO, TFrom>(TFrom entity) where TFrom : class where TO : class, new(){var outData = new TO();var outDataProperties = typeof(TO).GetProperties();foreach (System.Reflection.PropertyInfo property in entity.GetType().GetProperties()){var val = property.GetValue(entity);var findOutDataP = outDataProperties.FirstOrDefault(o => o.Name == property.Name && o.PropertyType == property.PropertyType);findOutDataP?.SetValue(outData, val);}return outData;}/// <summary>////// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>protected T CreateBll<T>() where T : BllBase, new(){var bll = new T();bll.IsTopBll = false;bll.SqlLiteDbContext = SqlLiteDbContext;bll.MySqlDbContext = MySqlDbContext;bll.InfluxClient = InfluxClient;return bll;}/// <summary>////// </summary>public virtual void Dispose(){foreach (var item in DalList){item.Dispose();}DalList.Clear();if (SqlLiteDbContext != null){if (IsTopBll){SqlLiteDbContext.Dispose();}SqlLiteDbContext = null;}if (MySqlDbContext != null){if (IsTopBll){MySqlDbContext.Dispose();}MySqlDbContext = null;}if (InfluxClient != null){if (IsTopBll){InfluxClient.Dispose();}InfluxClient = null;}}}
public class BllBase<TDbDal> : BllBase where TDbDal : DbDalBase, new(){/// <summary>////// </summary>public DbContext DbContext => Dal.DbContext;/// <summary>////// </summary>public void SaveChanges(){DbContext.SaveChanges();}private TDbDal _dal;/// <summary>////// </summary>public TDbDal Dal => _dal ??= CreateDal<TDbDal>();}
/// <summary>/// 查询条件/// </summary>public class QueryFilter{/// <summary>/// Where/// </summary>[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public List<FilterWhereItem> WhereItems { get; set; }/// <summary>/// 排序规则/// </summary>[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public List<FilterSortOrder> SortOrders { get; set; }}/// <summary>/// 排序规则/// </summary>public class FilterSortOrder{/// <summary>/// 字段名称/// </summary>[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public string PropertyName { get; set; }/// <summary>/// 排序方向/// </summary>[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public SortOrder Order { get; set; }}/// <summary>/// where条件/// </summary>public class FilterWhereItem{/// <summary>/// 字段名称/// </summary>[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public string PropertyName { get; set; }/// <summary>/// 值(必须是基础类型)/// </summary>[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public List<object> Values { get; set; }/// <summary>/// 逻辑运算/// </summary>[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]public Logical Logical { get; set; }}/// <summary>/// 逻辑运算/// </summary>public enum Logical{/// <summary>/// 模糊查询/// </summary>[Description("模糊查询")]Like = 0,/// <summary>/// 等于/// </summary>[Description("等于")]Eq = 1,/// <summary>/// 大于/// </summary>[Description("大于")]Gt = 2,/// <summary>/// 小于/// </summary>[Description("小于")]Lt = 3,/// <summary>/// 大于等于/// </summary>[Description("大于等于")]Gte = 4,/// <summary>/// 小于等于/// </summary>[Description("小于等于")]Lte = 5,/// <summary>/// IN查询/// </summary>[Description("IN查询")]In = 6}
public class ApiControllerBase<T, TBll, TDal> : ApiControllerBasewhere TBll : BllBase<TDal>, new()where T : EntityBase, new()where TDal : MySqlDalBase<T>, new(){/// <summary>////// </summary>public ApiControllerBase(){Bll = new TBll();}/// <summary>////// </summary>public TBll Bll { get; set; }/// <summary>/// 详情/// </summary>/// <param name="id">id</param>/// <returns>详情</returns>[Route("detail")][HttpGet][ApiInfo(needAuth: false)]public virtual T QueryDetail(string id){return Bll.Dal.FindById<T>(id);}/// <summary>/// 分页查询/// </summary>/// <param name="pageIndex">页码(从1开始)</param>/// <param name="pageSize">页大小</param>/// <param name="filter">查询条件</param>/// <returns>分页数据</returns>[Route("queryPage")][HttpPost][ApiInfo(needAuth: false)]public virtual SearchPage<T> QueryPage(int pageIndex, int pageSize, [FromBody] QueryFilter filter){return Bll.Dal.QueryPage<T>(pageIndex, pageSize, filter);}/// <summary>/// 条件查询/// </summary>/// <param name="filter">查询条件</param>/// <returns>数据</returns>[Route("query")][HttpPost][ApiInfo(needAuth: false)]public virtual IEnumerable<T> QueryByFilter([FromBody] QueryFilter filter){return Bll.Dal.Query<T>(filter);}/// <summary>/// 查询所有/// </summary>/// <returns>数据</returns>[Route("all")][HttpGet][ApiInfo(needAuth: false)]public virtual IEnumerable<T> QueryAll(){return Bll.Dal.FindAll<T>();}/// <summary>/// 更新/// </summary>/// <param name="data">数据</param>/// <returns>数据</returns>[Route("addOrUpdate")][HttpPost][ApiInfo(needAuth: false)]public virtual T AddOrUpdate([FromBody] T data){var addOrUpdate = Bll.Dal.AddOrUpdate(data);Bll.SaveChanges();return addOrUpdate;}/// <summary>/// 批量更新/// </summary>/// <param name="data">数据</param>/// <returns>数据</returns>[Route("addOrUpdateAll")][HttpPost][ApiInfo(needAuth: false)]public virtual IEnumerable<T> AddOrUpdateAll([FromBody] List<T> data){var addOrUpdateAll = Bll.Dal.AddOrUpdateAll(data);Bll.SaveChanges();return addOrUpdateAll;}/// <summary>/// 删除/// </summary>/// <param name="ids">ID集合</param>/// <returns>是否成功</returns>[Route("remove")][HttpPost][ApiInfo(needAuth: false)]public virtual bool Remove([FromBody] List<string> ids){var delete = Bll.Dal.Delete<T>(ids);Bll.SaveChanges();return delete;}}
/// <summary>////// </summary>public class DalBase : IDisposable{/// <summary>////// </summary>public virtual void Dispose(){}}/// <summary>////// </summary>public class DbDalBase : DalBase{/// <summary>////// </summary>public DbContext DbContext { get; set; }/// <summary>////// </summary>public override void Dispose(){base.Dispose();DbContext?.Dispose();}/// <summary>////// </summary>/// <param name="data"></param>/// <typeparam name="T"></typeparam>/// <returns></returns>public T Of<T>(T data) where T : EntityBase{data.id = string.IsNullOrWhiteSpace(data.id) ? SnowFlake.GenId().ToString() : data.id;data.createTime = data.createTime == new DateTime() ? DateTime.Now : data.createTime;data.createUserId = string.IsNullOrWhiteSpace(data.createUserId) ? LoginUserHelper.GetLoginUser()?.Id : data.createUserId;data.createUserName = string.IsNullOrWhiteSpace(data.createUserName) ? LoginUserHelper.GetLoginUser()?.UserName : data.createUserName;data.modifiedTime = data.modifiedTime == new DateTime() ? DateTime.Now : data.modifiedTime;data.modefiedUserId = string.IsNullOrWhiteSpace(data.modefiedUserId) ? LoginUserHelper.GetLoginUser()?.Id : data.modefiedUserId;data.modifiedUserName = string.IsNullOrWhiteSpace(data.modifiedUserName) ? LoginUserHelper.GetLoginUser()?.UserName : data.modifiedUserName;data.isDeleted = false;return data;}/// <summary>////// </summary>/// <param name="id"></param>/// <typeparam name="T"></typeparam>/// <returns></returns>public T FindById<T>(string id) where T : EntityBase{return DbContext.Set<T>().AsNoTracking().FirstOrDefault(p => p.id == id);}/// <summary>////// </summary>/// <param name="ids"></param>/// <typeparam name="T"></typeparam>/// <returns></returns>public List<T> FindByIds<T>(IEnumerable<string> ids) where T : EntityBase{return DbContext.Set<T>().AsNoTracking().Where(p => ids.Contains(p.id)).ToList();}/// <summary>////// </summary>/// <param name="data"></param>/// <typeparam name="T"></typeparam>/// <returns></returns>public T AddOrUpdate<T>(T data) where T : EntityBase{return AddOrUpdate(data, out _);}/// <summary>////// </summary>/// <param name="data"></param>/// <param name="isNewData"></param>/// <typeparam name="T"></typeparam>/// <returns></returns>public T AddOrUpdate<T>(T data, out bool isNewData) where T : EntityBase{isNewData = string.IsNullOrWhiteSpace(data.id) || !DbContext.Set<T>().Any(p => p.id == data.id);return isNewData ? DbContext.Set<T>().Add(Of(data)).Entity : DbContext.Set<T>().Update(Of(data)).Entity;}/// <summary>////// </summary>/// <typeparam name="T"></typeparam>/// <param name="dataEnumerable"></param>/// <returns></returns>public List<T> AddOrUpdateAll<T>(IEnumerable<T> dataEnumerable) where T : EntityBase{return AddOrUpdateAll(dataEnumerable, out _, out _);}/// <summary>////// </summary>/// <param name="dataEnumerable"></param>/// <param name="addEquatable"></param>/// <param name="updateEquatable"></param>/// <typeparam name="T"></typeparam>/// <returns></returns>public List<T> AddOrUpdateAll<T>(IEnumerable<T> dataEnumerable, out List<T> addEquatable, out List<T> updateEquatable) where T : EntityBase{addEquatable = new List<T>();updateEquatable = new List<T>();var addOrUpdateAll = dataEnumerable as T[] ?? dataEnumerable.ToArray();if (!addOrUpdateAll.Any()){return addOrUpdateAll.ToList();}List<T> result = new List<T>();List<string> ids = addOrUpdateAll.Select(p => p.id).Where(p => !string.IsNullOrWhiteSpace(p)).Distinct().ToList();var inHave = ids.Count < 1 ? new List<string>() : DbContext.Set<T>().Where(p => ids.Contains(p.id)).Select(p => p.id).ToList();var needUpdate = addOrUpdateAll.Where(p => inHave.Contains(p.id)).ToList();var needAdd = addOrUpdateAll.Where(p => !inHave.Contains(p.id)).ToList();foreach (var data in needAdd){DbContext.Set<T>().Add(Of(data));result.Add(data);addEquatable.Add(data);}foreach (var data in needUpdate){DbContext.Set<T>().Update(Of(data));result.Add(data);updateEquatable.Add(data);}return result;}/// <summary>////// </summary>/// <param name="data"></param>/// <typeparam name="T"></typeparam>/// <returns></returns>public bool Delete<T>(T data) where T : EntityBase, new(){var childTableAttributes = typeof(T).GetCustomAttributes<ChildTableAttribute>();foreach (var childTableAttribute in childTableAttributes){DeleteChild(childTableAttribute, new List<string> { data.id });}return DbContext.Set<T>().Where(p => p.id == data.id).Update(p => new T { isDeleted = true }) > 0;}/// <summary>////// </summary>/// <param name="ids"></param>/// <typeparam name="T"></typeparam>/// <returns></returns>public bool Delete<T>(List<string> ids) where T : EntityBase, new(){var childTableAttributes = typeof(T).GetCustomAttributes<ChildTableAttribute>();foreach (var childTableAttribute in childTableAttributes){DeleteChild(childTableAttribute, ids);}return DbContext.Set<T>().Where(p => ids.Contains(p.id)).Update(p => new T { isDeleted = true }) > 0;}/// <summary>////// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public List<T> FindAll<T>() where T : EntityBase{return DbContext.Set<T>().ToList();}/// <summary>////// </summary>/// <param name="filter"></param>/// <typeparam name="T"></typeparam>/// <returns></returns>public List<T> Query<T>(QueryFilter filter) where T : EntityBase{filter = EditFileName<T>(filter);IQueryable<T> queryable = DbContext.Set<T>().AsNoTracking();foreach (var filterWhereItem in filter.WhereItems){queryable = AddWhere(queryable, filterWhereItem);}queryable = AddSort(queryable, filter.SortOrders);return queryable.ToList();}/// <summary>/// 分页查询/// </summary>/// <param name="pageIndex">页码(1开始)</param>/// <param name="pageSize"></param>/// <param name="filter"></param>/// <returns></returns>public SearchPage<T> QueryPage<T>(int pageIndex, int pageSize, QueryFilter filter) where T : EntityBase{filter = EditFileName<T>(filter);IQueryable<T> queryable = DbContext.Set<T>().AsNoTracking();foreach (var filterWhereItem in filter?.WhereItems ?? new List<FilterWhereItem>()){queryable = AddWhere(queryable, filterWhereItem);}int count = queryable.Count();queryable = AddSort(queryable, filter?.SortOrders ?? new List<FilterSortOrder>());return new SearchPage<T>{totalDataCount = count,pageIndex = pageIndex,pageSize = pageSize,data = queryable.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList()};}/// <summary>/// 查询数量/// </summary>/// <param name="filter"></param>/// <typeparam name="T"></typeparam>/// <returns></returns>public int QueryCount<T>(QueryFilter filter) where T : EntityBase{filter = EditFileName<T>(filter);IQueryable<T> queryable = DbContext.Set<T>().AsNoTracking();foreach (var filterWhereItem in filter?.WhereItems ?? new List<FilterWhereItem>()){queryable = AddWhere(queryable, filterWhereItem);}int count = queryable.Count();return count;}private IQueryable<T> AddSort<T>(IQueryable<T> queryable, List<FilterSortOrder> filterSortOrders) where T : EntityBase{if (filterSortOrders == null || filterSortOrders.Count < 1){return queryable;}var sortOrders = filterSortOrders.Where(p => p.Order != SortOrder.Unspecified).ToList();if (sortOrders.Count < 1){return queryable;}StringBuilder stringBuilder = new StringBuilder();foreach (var filterSortOrder in sortOrders){stringBuilder.Append($"{filterSortOrder.PropertyName}{(filterSortOrder.Order == SortOrder.Ascending ? ", " : " desc, ")}");}return queryable.OrderBy(stringBuilder.ToString().Trim().Trim(','));}private IQueryable<T> AddWhere<T>(IQueryable<T> queryable, FilterWhereItem filterWhereItem) where T : EntityBase{switch (filterWhereItem.Logical){case Logical.Like:{if (filterWhereItem.Values != null&& filterWhereItem.Values.Count > 0&& !string.IsNullOrWhiteSpace(filterWhereItem.Values[0]?.ToString())){return queryable.Where($"{filterWhereItem.PropertyName}.Contains(@0)", filterWhereItem.Values[0].ToString());}}break;case Logical.Eq:if (filterWhereItem.Values != null&& filterWhereItem.Values.Count > 0&& filterWhereItem.Values[0] != null){return queryable.Where($"{filterWhereItem.PropertyName} == @0", ConvertArg<T>(filterWhereItem.PropertyName, filterWhereItem.Values));}break;case Logical.Gt:if (filterWhereItem.Values != null&& filterWhereItem.Values.Count > 0&& filterWhereItem.Values[0] != null){return queryable.Where($"{filterWhereItem.PropertyName} > @0", ConvertArg<T>(filterWhereItem.PropertyName, filterWhereItem.Values));}break;case Logical.Lt:if (filterWhereItem.Values != null&& filterWhereItem.Values.Count > 0&& filterWhereItem.Values[0] != null){return queryable.Where($"{filterWhereItem.PropertyName} < @0", ConvertArg<T>(filterWhereItem.PropertyName, filterWhereItem.Values));}break;case Logical.Gte:if (filterWhereItem.Values != null&& filterWhereItem.Values.Count > 0&& filterWhereItem.Values[0] != null){return queryable.Where($"{filterWhereItem.PropertyName} >= @0", ConvertArg<T>(filterWhereItem.PropertyName, filterWhereItem.Values));}break;case Logical.Lte:if (filterWhereItem.Values != null&& filterWhereItem.Values.Count > 0&& filterWhereItem.Values[0] != null){return queryable.Where($"{filterWhereItem.PropertyName} <= @0", ConvertArg<T>(filterWhereItem.PropertyName, filterWhereItem.Values));}break;case Logical.In:if (filterWhereItem.Values != null && filterWhereItem.Values.Count > 0){return queryable.Where($"@0.Contains({filterWhereItem.PropertyName})", ConvertArg<T>(filterWhereItem.PropertyName, filterWhereItem.Values, true));}break;default:return queryable;}return queryable;}private object ConvertArg<T>(string propertyName, List<object> value, bool b = false) where T : EntityBase{var propertyInfo = typeof(T).GetProperty(propertyName);if (propertyInfo == null){throw new Exception("不存在的属性:" + propertyName);}if (b){return value?.Select(p => ConvertData(propertyInfo.PropertyType, p)).ToList();}return value == null || value.Count < 1 ? null : ConvertData(propertyInfo.PropertyType, value[0]);}private object ConvertData(Type type, object o){if (o == null){return null;}if (type == typeof(string)){return o.ToString();}if (type == typeof(DateTime)){return DateTime.Parse(o.ToString() ?? "0000-00-00 00:00:00");}if (type.IsSubclassOf(typeof(Enum))){return Enum.Parse(type, o.ToString() ?? string.Empty);}var typeConverter = TypeDescriptor.GetConverter(type);return typeConverter.ConvertFrom(o);}private QueryFilter EditFileName<T>(QueryFilter filter) where T : EntityBase{if (filter == null){return null;}foreach (var filterSortOrder in filter.SortOrders ?? new List<FilterSortOrder>()){filterSortOrder.PropertyName = GetActualPropertyName<T>(filterSortOrder.PropertyName);}foreach (var filterWhereItem in filter.WhereItems ?? new List<FilterWhereItem>()){filterWhereItem.PropertyName = GetActualPropertyName<T>(filterWhereItem.PropertyName);}return filter;}private string GetActualPropertyName<T>(string propertyName) where T : EntityBase{foreach (var propertyInfo in typeof(T).GetProperties()){if (propertyInfo.Name.ToLower() == propertyName.ToLower()){return propertyInfo.Name;}}throw new Exception("无效的属性名称:" + propertyName);}private void DeleteChild(ChildTableAttribute childTableAttribute, List<string> ids){List<object> objects = DbContext.SetDynamic(childTableAttribute.ChildType.Name).Where($"@0.Contains({childTableAttribute.PropertyName})", ids).ToList();foreach (var entityBase in objects){var entityEntry = DbContext.Entry(entityBase);Of((EntityBase)entityEntry.Entity);((EntityBase)entityEntry.Entity).isDeleted = true;DbContext.Update(entityEntry.Entity);}}}
