| | |
| | | using Furion; |
| | | using Consul.Filtering; |
| | | 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.EntityFrameworkCore.Migrations; |
| | | using Microsoft.Extensions.Configuration; |
| | | using Newtonsoft.Json; |
| | | using System; |
| | |
| | | using System.Linq; |
| | | using System.Linq.Expressions; |
| | | using System.Text; |
| | | using System.Threading; |
| | | using System.Threading.Tasks; |
| | | using System.Timers; |
| | | |
| | | namespace FlexJobApi.Core |
| | | { |
| | | /// <summary> |
| | | /// 数据库工具 |
| | | /// </summary> |
| | | public static class DbUtils |
| | | { |
| | | /// <summary> |
| | | /// 获取树形数据路径 |
| | | /// </summary> |
| | | /// <typeparam name="TEntity"></typeparam> |
| | | /// <param name="parentId"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public static async Task<string> GetTreeDataPath<TEntity>( |
| | | Guid? parentId, |
| | | CancellationToken cancellationToken = default) |
| | | where TEntity : CommonEntity, ITreeData<TEntity>, new() |
| | | { |
| | | var rep = Db.GetRepository<TEntity>(); |
| | | if (parentId.HasValue) |
| | | { |
| | | var parent = await rep.AsQueryable().AsNoTracking() |
| | | .Where(it => it.Id == parentId) |
| | | .Select(it => new |
| | | { |
| | | it.Path, |
| | | it.Code |
| | | }) |
| | | .FirstOrDefaultAsync(cancellationToken); |
| | | var summary = typeof(TEntity).GetSummary(); |
| | | if (parent == null) throw Oops.Oh(EnumErrorCodeType.s404, $"上级{summary}"); |
| | | return $"{parent.Path}{parent.Code}/"; |
| | | } |
| | | else |
| | | { |
| | | return "/"; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 更新树形数据下级路径 |
| | | /// </summary> |
| | | /// <param name="oldPath"></param> |
| | | /// <param name="newPath"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public static async Task UpdateTreeDataChildrenPath<TEntity>( |
| | | string oldPath, |
| | | string newPath, |
| | | CancellationToken cancellationToken) |
| | | where TEntity : CommonEntity, ITreeData<TEntity>, new() |
| | | { |
| | | var rep = Db.GetRepository<TEntity>(); |
| | | var models = await rep.AsQueryable() |
| | | .Where(it => it.Path.StartsWith(oldPath)) |
| | | .ToListAsync(cancellationToken); |
| | | if (models.IsNotNull()) |
| | | { |
| | | foreach (var model in models) |
| | | { |
| | | model.Path = model.Path.Replace(oldPath, newPath); |
| | | } |
| | | await rep.UpdateAsync(models); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 查询选择器数据 |
| | | /// </summary> |
| | | /// <typeparam name="TEntity"></typeparam> |
| | | /// <typeparam name="TValue"></typeparam> |
| | | /// <typeparam name="TData"></typeparam> |
| | | /// <param name="request"></param> |
| | | /// <param name="getValue"></param> |
| | | /// <param name="getLabel"></param> |
| | | /// <param name="query"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public static async Task<List<SelectOption<TValue, TData>>> GetSelect<TEntity, TValue, TData>( |
| | | this SelectQuery<TValue, TData> request, |
| | | Func<TData, TValue> getValue, |
| | | Func<TData, string> getLabel, |
| | | Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null, |
| | | CancellationToken cancellationToken = default) |
| | | where TEntity : CommonEntity, new() |
| | | { |
| | | var rep = Db.GetRepository<TEntity>(); |
| | | var q = rep.AsQueryable().AsNoTracking(); |
| | | if (query != null) q = query(q); |
| | | else q = q.OrderBy(it => it.Sort).ThenBy(it => it.CreatedTime); |
| | | var models = await q |
| | | .ProjectToType<TData>() |
| | | .ToListAsync(cancellationToken); |
| | | var options = new List<SelectOption<TValue, TData>>(); |
| | | foreach (var model in models) |
| | | { |
| | | var option = new SelectOption<TValue, TData>(); |
| | | option.Data = model; |
| | | option.Value = getValue(model); |
| | | option.Label = getLabel(model); |
| | | options.Add(option); |
| | | } |
| | | return options; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 查询分页列表数据 |
| | | /// </summary> |
| | | /// <typeparam name="TEntity"></typeparam> |
| | | /// <typeparam name="TItem"></typeparam> |
| | | /// <param name="page"></param> |
| | | /// <param name="query"></param> |
| | | /// <param name="selector"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public static async Task<PagedListQueryResult<TItem>> GetPagedListAsync<TEntity, TItem>( |
| | | this PagedListQueryPageModel page, |
| | | Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null, |
| | | Expression<Func<TEntity, TItem>> selector = null, |
| | | CancellationToken cancellationToken = default) |
| | | where TEntity : CommonEntity, new() |
| | | where TItem : class, new() |
| | | { |
| | | var rep = Db.GetRepository<TEntity>(); |
| | | var q = rep.AsQueryable().AsNoTracking(); |
| | | if (query != null) q = query(q); |
| | | else q = q.OrderBy(it => it.Sort).ThenBy(it => it.CreatedTime); |
| | | if (page.OrderInput.IsNotNull()) |
| | | q = q.CustomOrderBy(page.OrderInput); |
| | | var s = selector == null |
| | | ? q.ProjectToType<TItem>() |
| | | : q.Select(selector); |
| | | var pagedList = await s.ToPagedListAsync(page.Page, page.Rows, cancellationToken); |
| | | var result = new PagedListQueryResult<TItem>(); |
| | | result.PageModel = page.Adapt<PagedListQueryResultPageModel>(); |
| | | result.PageModel.TotalCount = pagedList.TotalCount; |
| | | result.PageModel.TotalPage = pagedList.TotalPages; |
| | | result.Data = pagedList.Items.ToList(); |
| | | return result; |
| | | } |
| | | /// <summary> |
| | | /// 查询分页列表数据 |
| | | /// </summary> |
| | | /// <typeparam name="TResult"></typeparam> |
| | | /// <typeparam name="TItem"></typeparam> |
| | | /// <param name="page"></param> |
| | | /// <param name="q"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public static async Task<TResult> GetPagedListAsync<TResult, TItem>( |
| | | this PagedListQueryPageModel page, |
| | | IQueryable<TItem> q, |
| | | CancellationToken cancellationToken = default) |
| | | where TItem : class, new() |
| | | where TResult : PagedListQueryResult<TItem>, new() |
| | | { |
| | | if (page.OrderInput.IsNotNull()) |
| | | q = q.CustomOrderBy(page.OrderInput); |
| | | var pagedList = await q.ToPagedListAsync(page.Page, page.Rows, cancellationToken); |
| | | var result = new TResult(); |
| | | result.PageModel = page.Adapt<PagedListQueryResultPageModel>(); |
| | | result.PageModel.TotalCount = pagedList.TotalCount; |
| | | result.PageModel.TotalPage = pagedList.TotalPages; |
| | | result.Data = pagedList.Items.ToList(); |
| | | return result; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 查询分页列表数据 |
| | | /// </summary> |
| | | /// <typeparam name="TItem"></typeparam> |
| | | /// <param name="page"></param> |
| | | /// <param name="q"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public static Task<PagedListQueryResult<TItem>> GetPagedListAsync<TItem>( |
| | | this PagedListQueryPageModel page, |
| | | IQueryable<TItem> q, |
| | | CancellationToken cancellationToken = default) |
| | | where TItem : class, new() |
| | | { |
| | | return GetPagedListAsync<PagedListQueryResult<TItem>, TItem>(page, q, cancellationToken); |
| | | } |
| | | |
| | | public static IOrderedQueryable<T> CustomOrderBy<T>(this IQueryable<T> q, List<PagedListQueryPageModelOrderInput> orders) |
| | | { |
| | | ParameterExpression parameter = Expression.Parameter(typeof(T), "p"); |
| | | PagedListQueryPageModelOrderInput orderInput = orders[0]; |
| | | IOrderedQueryable<T> orderedQueryable = (orderInput.Order == EnumPagedListOrder.Asc) |
| | | ? OrderBy(q, orderInput.Property, parameter) |
| | | : OrderByDescending(q, orderInput.Property, parameter); |
| | | for (int i = 1; i < orders.Count; i++) |
| | | { |
| | | PagedListQueryPageModelOrderInput orderInput2 = orders[i]; |
| | | orderedQueryable = (orderInput2.Order == EnumPagedListOrder.Asc) |
| | | ? ThenBy(orderedQueryable, orderInput2.Property, parameter) |
| | | : ThenByDescending(orderedQueryable, orderInput2.Property, parameter); |
| | | } |
| | | |
| | | return orderedQueryable; |
| | | } |
| | | |
| | | private static IOrderedQueryable<T> Ordering<T>(IQueryable<T> source, ParameterExpression parameter, string propertyName, string methodName) |
| | | { |
| | | Type typeFromHandle = typeof(T); |
| | | MemberExpression memberExpression = Expression.PropertyOrField(parameter, propertyName); |
| | | LambdaExpression expression = Expression.Lambda(memberExpression, parameter); |
| | | MethodCallExpression expression2 = Expression.Call(typeof(Queryable), methodName, [typeFromHandle, memberExpression.Type], source.Expression, Expression.Quote(expression)); |
| | | return (IOrderedQueryable<T>)source.Provider.CreateQuery<T>(expression2); |
| | | } |
| | | |
| | | public static IOrderedQueryable<T> OrderBy<T>(IQueryable<T> source, string propertyName, ParameterExpression parameter) |
| | | { |
| | | return Ordering(source, parameter, propertyName, "OrderBy"); |
| | | } |
| | | |
| | | public static IOrderedQueryable<T> OrderByDescending<T>(IQueryable<T> source, string propertyName, ParameterExpression parameter) |
| | | { |
| | | return Ordering(source, parameter, propertyName, "OrderByDescending"); |
| | | } |
| | | |
| | | public static IOrderedQueryable<T> ThenBy<T>(IOrderedQueryable<T> source, string propertyName, ParameterExpression parameter) |
| | | { |
| | | return Ordering(source, parameter, propertyName, "ThenBy"); |
| | | } |
| | | |
| | | public static IOrderedQueryable<T> ThenByDescending<T>(IOrderedQueryable<T> source, string propertyName, ParameterExpression parameter) |
| | | { |
| | | return Ordering(source, parameter, propertyName, "ThenByDescending"); |
| | | } |
| | | |
| | | public static async Task<TResult> GetDetail<TEntity, TResult>( |
| | | this Guid id, |
| | | CancellationToken cancellationToken = default) |
| | | where TEntity : CommonEntity, new() |
| | | { |
| | | var rep = Db.GetRepository<TEntity>(); |
| | | return await rep.AsQueryable().AsNoTracking() |
| | | .Where(it => it.Id == id) |
| | | .GetDetail<TEntity, TResult>(cancellationToken); |
| | | } |
| | | |
| | | public static async Task<TResult> GetDetail<TEntity, TResult>( |
| | | this IQueryable<TEntity> q, |
| | | CancellationToken cancellationToken = default) |
| | | { |
| | | var model = await q |
| | | .ProjectToType<TResult>() |
| | | .FirstOrDefaultAsync(cancellationToken); |
| | | if (model == null) |
| | | { |
| | | var summary = await typeof(TEntity).GetSummary(); |
| | | throw Oops.Oh(EnumErrorCodeType.s404, $"{summary ?? "信息"}"); |
| | | } |
| | | return model; |
| | | } |
| | | |
| | | /// <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> SetIsDisabled<TEntity>( |
| | | this SetIsDisabledCommand request, |
| | | Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null, |
| | | CancellationToken cancellationToken = default) |
| | | where TEntity : CommonEntity, IIsDisabled, 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) && it.IsDisabled != request.IsDisabled) |
| | | .ToListAsync(); |
| | | foreach (var entity in entities) |
| | | { |
| | | entity.IsDisabled = request.IsDisabled; |
| | | } |
| | | return entities.Count; |
| | | } |
| | | |
| | | /// <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; |
| | | } |
| | | |
| | | public static async Task<Guid> UpdateData<TEntity, TRequest>( |
| | | this IQueryable<TEntity> q, |
| | | TRequest request, |
| | | Action<TEntity> update = null, |
| | | CancellationToken cancellationToken = default) |
| | | where TEntity : CommonEntity, new() |
| | | { |
| | | var rep = Db.GetRepository<TEntity>(); |
| | | var entity = await q.FirstOrDefaultAsync(); |
| | | if (entity == null) |
| | | { |
| | | var summary = await typeof(TEntity).GetSummary(); |
| | | throw Oops.Oh(EnumErrorCodeType.s404, $"{summary ?? "信息"}"); |
| | | } |
| | | |
| | | if (update != null) update(entity); |
| | | else request.Adapt(entity); |
| | | await rep.UpdateAsync(entity); |
| | | return entity.Id; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 保存数据 |
| | | /// </summary> |
| | | /// <typeparam name="TEntity"></typeparam> |
| | | /// <typeparam name="TRequest"></typeparam> |
| | | /// <param name="request"></param> |
| | | /// <param name="query"></param> |
| | | /// <param name="checkExist"></param> |
| | | /// <param name="update"></param> |
| | | /// <param name="cancellationToken"></param> |
| | | /// <returns></returns> |
| | | public static async Task<Guid> SaveData<TEntity, TRequest>( |
| | | this TRequest request, |
| | | Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null, |
| | | Expression<Func<TEntity, bool>> checkExist = null, |
| | | Action<TEntity> update = 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 (checkExist != null && await rep.AsQueryable().AsNoTracking().AnyAsync(checkExist)) |
| | | throw Oops.Oh(EnumErrorCodeType.s405, $"{summary ?? "信息"}"); |
| | | if (request.Id.HasValue) |
| | | { |
| | | var q = rep.AsQueryable(); |
| | | if (query != null) q = query(q); |
| | | var entity = await q.FirstOrDefaultAsync(it => it.Id == request.Id, cancellationToken); |
| | | if (entity == null) throw Oops.Oh(EnumErrorCodeType.s404, $"{summary ?? "信息"}"); |
| | | if (update != null) update(entity); |
| | | else request.Adapt(entity); |
| | | await rep.UpdateAsync(entity); |
| | | return entity.Id; |
| | | } |
| | | else |
| | | { |
| | | var entity = new TEntity(); |
| | | if (update != null) update(entity); |
| | | else request.Adapt(entity); |
| | | await rep.InsertAsync(entity); |
| | | return entity.Id; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 生成实体 |
| | | /// </summary> |
| | |
| | | /// <returns></returns> |
| | | public static async Task BuildEntity(ModelBuilder modelBuilder, Type dbContextLocator = null) |
| | | { |
| | | var xmlDoc = await XmlDocUtils.GetXmlDocAsync(); |
| | | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) |
| | | if (App.GetService<IMigrator>() != null) |
| | | { |
| | | Console.WriteLine($"正在生成表:{entityType.Name}"); |
| | | // 获取实体类的XML注释,并设置为表注释 |
| | | var entityBuilder = modelBuilder.Entity(entityType.ClrType); |
| | | string typeComment = (await entityType.ClrType.GetXmlDocMemberAsync(xmlDoc))?.Summary; |
| | | if (!string.IsNullOrEmpty(typeComment)) |
| | | var xmlDoc = await XmlDocUtils.GetXmlDocAsync(); |
| | | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) |
| | | { |
| | | Console.WriteLine($"正在生成表注释:{entityType.Name}-{typeComment}"); |
| | | entityBuilder.ToTable(it => it.HasComment(typeComment)); |
| | | } |
| | | // 获取实体属性的XML注释,并设置为列注释 |
| | | var properties = entityType.ClrType.GetProperties() |
| | | .Where(p => |
| | | p.CanRead |
| | | && p.CanWrite |
| | | && !typeof(System.Collections.ICollection).IsAssignableFrom(p.PropertyType) |
| | | && (p.PropertyType.IsClass ? p.PropertyType.FullName.Contains("System.") : true)); |
| | | foreach (var property in properties) |
| | | { |
| | | string propComment = (await property.GetXmlDocMemberAsync(xmlDoc))?.Summary; |
| | | if (!string.IsNullOrEmpty(propComment)) |
| | | Console.WriteLine($"正在生成表:{entityType.Name}"); |
| | | // 获取实体类的XML注释,并设置为表注释 |
| | | var entityBuilder = modelBuilder.Entity(entityType.ClrType); |
| | | string typeComment = (await entityType.ClrType.GetXmlDocMemberAsync(xmlDoc))?.Summary; |
| | | if (!string.IsNullOrEmpty(typeComment)) |
| | | { |
| | | Console.WriteLine($"正在生成属性注释:{property.Name}-{propComment}"); |
| | | entityBuilder.Property(property.Name).HasComment(propComment); |
| | | Console.WriteLine($"正在生成表注释:{entityType.Name}-{typeComment}"); |
| | | entityBuilder.ToTable(it => it.HasComment(typeComment)); |
| | | } |
| | | // 获取实体属性的XML注释,并设置为列注释 |
| | | var properties = entityType.ClrType.GetProperties() |
| | | .Where(p => |
| | | p.CanRead |
| | | && p.CanWrite |
| | | && !typeof(System.Collections.ICollection).IsAssignableFrom(p.PropertyType) |
| | | && (p.PropertyType.IsClass ? p.PropertyType.FullName.Contains("System.") : true)); |
| | | foreach (var property in properties) |
| | | { |
| | | string propComment = (await property.GetXmlDocMemberAsync(xmlDoc))?.Summary; |
| | | if (!string.IsNullOrEmpty(propComment)) |
| | | { |
| | | Console.WriteLine($"正在生成属性注释:{property.Name}-{propComment}"); |
| | | entityBuilder.Property(property.Name).HasComment(propComment); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) |
| | | { |
| | | if (typeof(CommonEntity).IsAssignableFrom(entityType.ClrType)) |
| | | { |
| | | // 构建筛选条件:IsDeleted == false |
| | |
| | | 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 logier = JwtUtils.GetCurrentLogier(); |
| | | var traceId = App.GetTraceId(); |
| | | |
| | | // 获取所有已更改的实体 |
| | | foreach (var entity in entities) |
| | |
| | | } |
| | | |
| | | // 赋值用户信息Id |
| | | prop = entity.Property(nameof(CommonEntity.CreatedUserInfoId)); |
| | | prop = entity.Property(nameof(CommonEntity.CreatedUserId)); |
| | | if (prop != null && prop.CurrentValue == null) |
| | | { |
| | | prop.CurrentValue = logier?.UserInfoId; |
| | | prop.CurrentValue = logier?.Id; |
| | | } |
| | | |
| | | // 赋值企业Id |
| | | prop = entity.Property(nameof(CommonEntity.CreatedEnterpriseId)); |
| | | if (prop != null && prop.CurrentValue == null) |
| | | { |
| | | prop.CurrentValue = logier?.EnterpriseId; |
| | | } |
| | | |
| | | // 赋值跟踪Id |
| | | prop = entity.Property(nameof(CommonEntity.TraceId)); |
| | | if (prop != null) |
| | | if (prop != null && prop.CurrentValue == null && traceId.IsNotNull()) |
| | | { |
| | | prop.CurrentValue = App.GetTraceId(); |
| | | prop.CurrentValue = traceId; |
| | | } |
| | | } |
| | | else |
| | |
| | | } |
| | | |
| | | // 赋值用户信息Id |
| | | prop = entity.Property(nameof(CommonEntity.UpdatedUserInfoId)); |
| | | prop = entity.Property(nameof(CommonEntity.UpdatedUserId)); |
| | | if (prop != null) |
| | | { |
| | | prop.CurrentValue = logier?.UserInfoId; |
| | | prop.CurrentValue = logier?.Id; |
| | | } |
| | | |
| | | // 赋值跟踪Id |
| | | prop = entity.Property(nameof(CommonEntity.TraceId)); |
| | | if (prop != null) |
| | | if (prop != null && traceId.IsNotNull()) |
| | | { |
| | | prop.CurrentValue = App.GetTraceId(); |
| | | prop.CurrentValue = traceId; |
| | | } |
| | | |
| | | // 软删除 |
| | |
| | | continue; |
| | | } |
| | | |
| | | Db.GetRepository<DbAuditLog, LogDbContextLocator>().InsertNow(new DbAuditLog |
| | | var log = new DbAuditLog |
| | | { |
| | | Id = IDGen.NextID(), |
| | | TableName = entityType.Name, |
| | | PrimaryKey = (Guid)entity.Property("Id").CurrentValue, |
| | | NewValues = entity.State == EntityState.Added || entity.State == EntityState.Modified |
| | | ? GetPropertyValuesAsJson(entity) |
| | | : null, |
| | | OldValues = entity.State == EntityState.Deleted || entity.State == EntityState.Modified |
| | | ? GetPropertyValuesAsJson(entity, entity.State == EntityState.Modified) |
| | | : null, |
| | | Operate = entity.State == EntityState.Added |
| | | ? EnumDbAuditOperate.Added |
| | | : entity.State == EntityState.Modified |
| | | ? EnumDbAuditOperate.Modified |
| | | : EnumDbAuditOperate.Deleted, |
| | | TraceId = App.GetTraceId(), |
| | | CreatedTime = DateTime.Now, |
| | | CreatedUserInfoId = logier?.UserInfoId, |
| | | }); |
| | | CreatedUserId = logier?.Id, |
| | | CreatedEnterpriseId = logier?.EnterpriseId |
| | | }; |
| | | log.Operate = |
| | | entity.State == EntityState.Added |
| | | ? EnumDbAuditOperate.Added |
| | | : entity.State == EntityState.Modified |
| | | ? EnumDbAuditOperate.Modified |
| | | : EnumDbAuditOperate.Deleted; |
| | | if (entity.Property(nameof(CommonEntity.IsDeleted)).CurrentValue is bool isDeleted && isDeleted == true) |
| | | { |
| | | log.Operate = EnumDbAuditOperate.Deleted; |
| | | } |
| | | log.NewValues = |
| | | log.Operate == EnumDbAuditOperate.Deleted |
| | | ? null |
| | | : JsonConvert.SerializeObject(entity.Properties |
| | | .Where(p => log.Operate == EnumDbAuditOperate.Modified |
| | | ? p.IsModified |
| | | : true) |
| | | .ToDictionary(p => p.Metadata.Name, p => p.CurrentValue)); |
| | | log.OldValues = |
| | | log.Operate == EnumDbAuditOperate.Added |
| | | ? null |
| | | : JsonConvert.SerializeObject(entity.Properties |
| | | .Where(p => log.Operate == EnumDbAuditOperate.Modified |
| | | ? p.IsModified |
| | | : true) |
| | | .ToDictionary(p => p.Metadata.Name, p => p.OriginalValue)); |
| | | Db.GetRepository<DbAuditLog, LogDbContextLocator>().InsertNow(log); |
| | | } |
| | | } |
| | | |
| | | private static string GetPropertyValuesAsJson(EntityEntry entry, bool getOldValues = false) |
| | | { |
| | | var properties = entry.Properties |
| | | .Where(p => getOldValues ? p.IsModified : true) |
| | | .ToDictionary(p => p.Metadata.Name, p => getOldValues ? p.OriginalValue : p.CurrentValue); |
| | | |
| | | return JsonConvert.SerializeObject(properties); |
| | | } |
| | | } |
| | | } |