sunpengfei
2025-08-06 bc6813b74e9a390eae2181d460c647445b7cb25a
FlexJobApi.Core/Utils/DbUtils/DbUtils.cs
@@ -1,22 +1,204 @@
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>
        /// <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>> ToPagedListAsync<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);
            q = q.OrderBy(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="T"></typeparam>
        /// <param name="q"></param>
        /// <param name="orders"></param>
        /// <returns></returns>
        public static IQueryable<T> OrderBy<T>(this IQueryable<T> q, List<PagedListQueryPageModelOrderInput> orders)
        {
            if (orders.IsNull()) return q;
            var entityType = typeof(T);
            int index = 0;
            var props = entityType.GetProperties();
            foreach (var order in orders)
            {
                if (string.IsNullOrEmpty(order.Property)) continue;
                // 获取排序字段的属性信息
                var propertyInfo = props.FirstOrDefault(it => it.Name.Equals(order.Property, StringComparison.OrdinalIgnoreCase));
                if (propertyInfo == null) throw Oops.Oh(EnumErrorCodeType.s404, $"该排序字段{order.Property}");
                // 创建表达式树
                var parameter = Expression.Parameter(entityType, "x");
                var propertyAccess = Expression.Property(parameter, propertyInfo);
                var lambda = Expression.Lambda(propertyAccess, parameter);
                string methodName;
                if (index == 0)
                {
                    // 首次排序
                    methodName = order.Order == EnumPagedListOrder.Asc
                        ? "OrderBy"
                        : "OrderByDescending";
                }
                else
                {
                    // 二次及以后排序
                    methodName = order.Order == EnumPagedListOrder.Asc
                        ? "ThenBy"
                        : "ThenByDescending";
                }
                // 调用相应的排序方法
                var resultExpression = Expression.Call(
                    typeof(Queryable),
                    methodName,
                    [entityType, propertyInfo.PropertyType],
                    q.Expression,
                    Expression.Quote(lambda)
                );
                q = q.Provider.CreateQuery<T>(resultExpression);
                index++;
            }
            return q;
        }
        /// <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> SetIsDisable<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;
        }
        /// <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>
@@ -67,8 +249,15 @@
                    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)
        {
            // 获取当前事件对应上下文