| | |
| | | using Furion; |
| | | using Furion.DatabaseAccessor; |
| | | using Furion.DistributedIDGenerator; |
| | | using Furion.FriendlyException; |
| | | using Mapster; |
| | | using Microsoft.EntityFrameworkCore; |
| | | using Microsoft.EntityFrameworkCore.ChangeTracking; |
| | | using Microsoft.EntityFrameworkCore.Diagnostics; |
| | | using Microsoft.EntityFrameworkCore.Metadata.Builders; |
| | | using Microsoft.Extensions.Configuration; |
| | | using Newtonsoft.Json; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Linq.Expressions; |
| | | using System.Text; |
| | | using System.Threading; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace FlexJobApi.Core |
| | | { |
| | | /// <summary> |
| | | /// 数据库工具 |
| | | /// </summary> |
| | | public static class DbUtils |
| | | { |
| | | /// <summary> |
| | | /// 生成实体注释 |
| | | /// 删除数据 |
| | | /// </summary> |
| | | /// <typeparam name="TEntity"></typeparam> |
| | | /// <param name="request"></param> |
| | | /// <param name="query"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public static async Task<int> DeleteData<TEntity>(this DeleteDataCommand request, Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null, CancellationToken cancellationToken = default) |
| | | where TEntity : CommonEntity, new() |
| | | { |
| | | var rep = Db.GetRepository<TEntity>(); |
| | | var q = rep.AsQueryable(); |
| | | if (query != null) q = query(q); |
| | | var entities = await q |
| | | .Where(it => request.Ids.Contains(it.Id)) |
| | | .ToListAsync(cancellationToken); |
| | | return entities.Any() |
| | | ? await rep.DeleteNowAsync(entities, cancellationToken) |
| | | : 0; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 保存数据 |
| | | /// </summary> |
| | | /// <typeparam name="TEntity"></typeparam> |
| | | /// <typeparam name="TRequest"></typeparam> |
| | | /// <param name="request"></param> |
| | | /// <param name="checkExist"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public static async Task<Guid> SaveData<TEntity, TRequest>(this TRequest request, Func<IQueryable<TEntity>, TEntity, TRequest, bool> checkExist = null, CancellationToken cancellationToken = default) |
| | | where TEntity : CommonEntity, new() |
| | | where TRequest : SaveDataCommand, new() |
| | | { |
| | | var xmlDoc = await XmlDocUtils.GetXmlDocAsync(); |
| | | var summary = await typeof(TEntity).GetSummary(xmlDoc); |
| | | var rep = Db.GetRepository<TEntity>(); |
| | | if (request.Id.HasValue) |
| | | { |
| | | var entity = await rep.AsQueryable().FirstOrDefaultAsync(it => it.Id == request.Id, cancellationToken); |
| | | if (entity == null) throw Oops.Oh(EnumErrorCodeType.s404, $"该{summary ?? "信息"}"); |
| | | if (checkExist != null && checkExist(rep.AsQueryable().AsNoTracking(), entity, request)) throw Oops.Oh(EnumErrorCodeType.s405, $"该{summary ?? "信息"}"); |
| | | request.Adapt(entity); |
| | | await rep.UpdateAsync(entity); |
| | | return entity.Id; |
| | | } |
| | | else |
| | | { |
| | | var entity = new TEntity(); |
| | | if (checkExist != null && checkExist(rep.AsQueryable().AsNoTracking(), entity, request)) throw Oops.Oh(EnumErrorCodeType.s405, $"该{summary ?? "信息"}"); |
| | | request.Adapt(entity); |
| | | await rep.InsertAsync(entity); |
| | | return entity.Id; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 生成实体 |
| | | /// </summary> |
| | | /// <param name="modelBuilder"></param> |
| | | /// <param name="dbContextLocator"></param> |
| | | /// <returns></returns> |
| | | public static async Task BuildEntityComment(ModelBuilder modelBuilder, Type dbContextLocator = null) |
| | | public static async Task BuildEntity(ModelBuilder modelBuilder, Type dbContextLocator = null) |
| | | { |
| | | var xmlDoc = await XmlDocUtils.GetXmlDocAsync(); |
| | | var entityTypes = App.Assemblies |
| | | .Where(it => it.FullName.Contains("FlexJob")) |
| | | .SelectMany(it => it.GetTypes()) |
| | | .Where(it => |
| | | it.IsClass |
| | | && !it.IsAbstract |
| | | && typeof(IPrivateEntity).IsAssignableFrom(it) |
| | | && (dbContextLocator == null |
| | | ? it.BaseType == typeof(CommonEntity) |
| | | : it.BaseType.GenericTypeArguments.Any(it => it == dbContextLocator))) |
| | | .ToList(); |
| | | foreach (var entityType in entityTypes) |
| | | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) |
| | | { |
| | | Console.WriteLine($"正在生成表:{entityType.Name}"); |
| | | // 获取实体类的XML注释,并设置为表注释 |
| | | var entityBuilder = modelBuilder.Entity(entityType); |
| | | string typeComment = (await entityType.GetXmlDocMemberAsync(xmlDoc))?.Summary; |
| | | var entityBuilder = modelBuilder.Entity(entityType.ClrType); |
| | | string typeComment = (await entityType.ClrType.GetXmlDocMemberAsync(xmlDoc))?.Summary; |
| | | if (!string.IsNullOrEmpty(typeComment)) |
| | | { |
| | | Console.WriteLine($"正在生成表注释:{entityType.Name}-{typeComment}"); |
| | | entityBuilder.ToTable(it => it.HasComment(typeComment)); |
| | | } |
| | | // 获取实体属性的XML注释,并设置为列注释 |
| | | var properties = entityType.GetProperties() |
| | | var properties = entityType.ClrType.GetProperties() |
| | | .Where(p => |
| | | p.CanRead |
| | | && p.CanWrite |
| | |
| | | entityBuilder.Property(property.Name).HasComment(propComment); |
| | | } |
| | | } |
| | | |
| | | if (typeof(CommonEntity).IsAssignableFrom(entityType.ClrType)) |
| | | { |
| | | // 构建筛选条件:IsDeleted == false |
| | | var parameter = Expression.Parameter(entityType.ClrType, "e"); |
| | | var property = Expression.Property(parameter, "IsDeleted"); |
| | | var constant = Expression.Constant(false); |
| | | var equal = Expression.Equal(property, constant); |
| | | var lambda = Expression.Lambda(equal, parameter); |
| | | |
| | | // 添加全局筛选器 |
| | | modelBuilder.Entity(entityType.ClrType).HasQueryFilter(lambda); |
| | | } |
| | | } |
| | | |
| | | Console.WriteLine("数据库链接地址:" + App.Configuration.GetConnectionString("FlexJobApi")); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 数据变更事件 |
| | | /// </summary> |
| | | /// <param name="eventData"></param> |
| | | /// <param name="result"></param> |
| | | public static void SavingChangesEvent(DbContextEventData eventData, InterceptionResult<int> result) |
| | | { |
| | | // 获取当前事件对应上下文 |
| | |
| | | var prop = entity.Property(nameof(CommonEntity.CreatedTime)); |
| | | if (prop != null && prop.CurrentValue?.ToDateTime() == null) |
| | | { |
| | | prop.CurrentValue = DateTime.Now; |
| | | prop.CurrentValue = DateTimeOffset.Now; |
| | | } |
| | | |
| | | // 生成Id |
| | |
| | | { |
| | | prop.CurrentValue = logier?.UserInfoId; |
| | | } |
| | | |
| | | // 赋值跟踪Id |
| | | prop = entity.Property(nameof(CommonEntity.TraceId)); |
| | | if (prop != null) |
| | | { |
| | | prop.CurrentValue = App.GetTraceId(); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // 赋值修改日期 |
| | | var prop = entity.Property(nameof(CommonEntity.UpdatedTime)); |
| | | if (prop != null && prop.CurrentValue?.ToDateTime() == null) |
| | | if (prop != null) |
| | | { |
| | | prop.CurrentValue = DateTime.Now; |
| | | prop.CurrentValue = DateTimeOffset.Now; |
| | | } |
| | | |
| | | // 赋值用户信息Id |
| | | prop = entity.Property(nameof(CommonEntity.UpdatedUserInfoId)); |
| | | if (prop != null && prop.CurrentValue == null) |
| | | if (prop != null) |
| | | { |
| | | prop.CurrentValue = logier?.UserInfoId; |
| | | } |
| | | |
| | | // 赋值跟踪Id |
| | | prop = entity.Property(nameof(CommonEntity.TraceId)); |
| | | if (prop != null && prop.CurrentValue == null) |
| | | if (prop != null) |
| | | { |
| | | prop.CurrentValue = App.GetTraceId(); |
| | | } |
| | |
| | | entity.State = EntityState.Modified; |
| | | |
| | | prop = entity.Property(nameof(CommonEntity.IsDeleted)); |
| | | if (prop != null && prop.CurrentValue == null) |
| | | if (prop != null) |
| | | { |
| | | prop.CurrentValue = true; |
| | | } |
| | |
| | | : EnumDbAuditOperate.Deleted, |
| | | TraceId = App.GetTraceId(), |
| | | CreatedTime = DateTime.Now, |
| | | CreatedUserInfoId = logier.UserInfoId, |
| | | CreatedUserInfoId = logier?.UserInfoId, |
| | | }); |
| | | } |
| | | } |
| | |
| | | .ToDictionary(p => p.Metadata.Name, p => getOldValues ? p.OriginalValue : p.CurrentValue); |
| | | |
| | | return JsonConvert.SerializeObject(properties); |
| | | } |
| | | |
| | | public static void OnCreating(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator) |
| | | { |
| | | var metadata = entityBuilder.Metadata; |
| | | |
| | | var parameter = Expression.Parameter(metadata.ClrType, "e"); |
| | | var property = Expression.Property(parameter, nameof(CommonEntity.IsDeleted)); |
| | | var falseConstant = Expression.Constant(false, typeof(bool)); |
| | | var fakeDeleteQueryFilterExpression = Expression.Lambda( |
| | | Expression.Equal(property, falseConstant), |
| | | parameter |
| | | ); |
| | | if (fakeDeleteQueryFilterExpression == null) return; |
| | | entityBuilder.HasQueryFilter(fakeDeleteQueryFilterExpression); |
| | | } |
| | | } |
| | | } |