using Microsoft.EntityFrameworkCore; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using VOL.Core.EFDbContext; using VOL.Core.Enums; using VOL.Core.Extensions; using VOL.Core.UserManager; using VOL.Core.Utilities; using VOL.Entity; using VOL.Entity.DomainModels; using VOL.Entity.SystemModels; namespace VOL.Core.BaseProvider { public static class ApplicationServiceBaseUpdateOrAddExtensions { private static MethodInfo ConvertDetailDataMethod { get { return typeof(ApplicationServiceBaseUpdateOrAddExtensions) .GetMethods(BindingFlags.NonPublic | BindingFlags.Static) .First(m => m.Name == nameof(ConvertDetailData)); } } public static (WebResponseContent res, TEntity entity) GetAddEntityData( this SaveModel saveDataModel, ServiceBase service) where TEntity : BaseEntity where TRepository : IRepository { WebResponseContent baseWebResponse = new(); if (service.AddOnExecute != null) { baseWebResponse = service.AddOnExecute(saveDataModel); if (service.ResponseIsError) return (baseWebResponse, null); } if ((saveDataModel?.MainData?.Count ?? 0) == 0) return (baseWebResponse.Set(ResponseType.ParametersLack, false), null); saveDataModel.DetailData = saveDataModel.DetailData?.Where(x => x.Count > 0).ToList(); Type type = typeof(TEntity); saveDataModel.MainData .SetDataVersionDefaultValue(saveDataModel.DataVersionField) //数据版本号管理 .SetAuditDefaultValue()//审批字段默认值 .SetLogicDelValue() //设置默认创建人信息 .SetCreateDefaultVal(); //设置默认逻辑删除值 string validReslut = type.ValidateDicInEntity(saveDataModel.MainData, true, false, ApplicationServiceBaseConfig.UserIgnoreFields); if (!string.IsNullOrEmpty(validReslut)) return (baseWebResponse.Error(validReslut), null); //设置主键默认值 saveDataModel.MainData.SetPrimaryKeyDefaultValue(); //实体转换与租户设置 TEntity mainEntity = saveDataModel.MainData.DicToEntity(); baseWebResponse = ValidationEntityUnique(mainEntity, true); if (!baseWebResponse.Status) return (baseWebResponse, null); baseWebResponse = saveDataModel.ConvertDetailEntity(service, mainEntity, true); return (baseWebResponse, mainEntity); } public static (WebResponseContent res, TEntity entity) GetUpdateEntityData( this SaveModel saveDataModel, ServiceBase service) where TEntity : BaseEntity where TRepository : IRepository { WebResponseContent baseWebResponse = new(); if (service.UpdateOnExecute != null) { baseWebResponse = service.UpdateOnExecute(saveDataModel); if (service.ResponseIsError) return (baseWebResponse, null); } if ((saveDataModel?.MainData?.Count ?? 0) == 0) return (baseWebResponse.Set(ResponseType.ParametersLack, false), null); saveDataModel.DetailData = saveDataModel.DetailData?.Where(x => x.Count > 0).ToList(); Type type = typeof(TEntity); saveDataModel.MainData.SetModifyDefaultVal(); //设置编辑人信息 string validReslut = type.ValidateDicInEntity( saveDataModel.MainData, true, false, ApplicationServiceBaseConfig.UserIgnoreFields, requireAllField:false); if (!string.IsNullOrEmpty(validReslut)) return (baseWebResponse.Error(validReslut), null); TEntity mainEntity = saveDataModel.MainData.DicToEntity(); baseWebResponse = ValidationEntityUnique(mainEntity, false); if (!baseWebResponse.Status) return (baseWebResponse, null); //检查版本号 baseWebResponse = service.ValidationDataVersion(mainEntity, saveDataModel); if (service.ResponseIsError) return (baseWebResponse, null); //二、三明细表转换 baseWebResponse = saveDataModel.ConvertDetailEntity(service, mainEntity, false); // if (service.CheckResponseResult()) return baseWebResponse; return (baseWebResponse, mainEntity); } public static WebResponseContent ConvertDetailEntity( this SaveModel saveModel, ServiceBase service, TEntity mainEntity, bool isAdd = true) where TEntity : BaseEntity where TRepository : IRepository { service.MultipleTableEntity = new ApplicationServiceBaseMultipleTableEntity(); WebResponseContent webResponse = new(true); var detailTypes = typeof(TEntity).GetCustomAttribute().DetailTable; //1级表(主表) int lv = 1; if ((saveModel.DetailData != null && saveModel.DetailData.Count > 0) || saveModel.DelKeys?.Count > 0) { saveModel.DetailData ??= []; var generic = ConvertDetailDataMethod.MakeGenericMethod(typeof(TEntity), detailTypes[0]); webResponse = generic.Invoke(null, [mainEntity, saveModel, saveModel.DetailData, saveModel.DelKeys, service.MultipleTableEntity, isAdd, lv]) as WebResponseContent; } return webResponse; } /// /// 明细表校验与转换 /// /// /// /// /// /// private static WebResponseContent ConvertDetailData( TMain mainEntity, SaveModel saveModel, List> dic, List delKeys, ApplicationServiceBaseMultipleTableEntity multipleTableEntity, bool isAdd = true, int lv = 1) where TMain : class where TDetail : class { //二级子表如果是新建的对象,三级表不应该再调用添加 WebResponseContent webResponse = new(); Type detailType = typeof(TDetail); var subDetailTypes = detailType.GetCustomAttribute().DetailTable ?? []; var ignoreSubRowFields = subDetailTypes.Select(s => s.Name).ToList(); //获取主表主键验证 string foreignKey = typeof(TMain).GetForeignKey(detailType.Name); //isAdd && if (!string.IsNullOrEmpty(foreignKey)) { ignoreSubRowFields.Add(foreignKey); } string msg = detailType.ValidateDicInEntity(dic, true, false, ignoreSubRowFields.ToArray()); if (!string.IsNullOrEmpty(msg)) { return webResponse.Error($"{detailType.GetEntityTableCnName()}:{msg}"); } List list = []; if (!multipleTableEntity.Data.TryGetValue(detailType, out EntityData entityData)) { entityData = new EntityData(); multipleTableEntity.Data[detailType] = entityData; } //删除的数据 entityData.DelKeys = delKeys; //三细明细表传的是null值 if (mainEntity == null) { return webResponse.OK(); } var mainKeyProperty = typeof(TMain).GetKeyProperty(); var mainKeyValue = mainKeyProperty.GetValue(mainEntity); foreach (var item in dic) { bool detailIsAdd = isAdd || item.IsTypeAdd(detailType); //新增数据 if (detailIsAdd) { item.SetLogicDelValue() .SetCreateDefaultVal() //设置自定义主表主键字段的值 .SetPrimaryKeyDefaultValue(foreignKey, mainKeyValue); } else { //记录编辑的字段 if (entityData.UpdateFields.Count == 0) { entityData.UpdateFields = [.. FilterUpdateFields(detailType, item.Select(s => s.Key))]; } //编辑数据 item.SetModifyDefaultVal(); } TDetail detailData = item.DicToEntity(); ; list.Add(detailData); //添加的数据 if (detailIsAdd) { entityData.AddList.Add(detailData); //二级主表为添加的数据时,三级子表标记不单独写入(编辑数据时用) if (isAdd && lv > 1) { entityData.InsertDb = false; } } else { //编辑的数据 entityData.UpdateList.Add(detailData); } } if (list?.Count > 0) { //给主表写入明细表对象(二级明细表是添加的数据,三级明细表应该标记不手动写入数据库) var property = typeof(TMain).GetProperty(detailType.GetEntityTableName(false)); property?.SetValue(mainEntity, list); } return webResponse.OK(); } private static WebResponseContent ValidationEntityHasDetail(Type detailType, string table) { WebResponseContent webResponse = new(); if (detailType == null) { return webResponse.Error($"未找到明细表[{table}]配置,请重新配置主表的明细表,再点生成model"); } return webResponse.OK(); } private static string[] FilterUpdateFields(Type entityType, IEnumerable rawFields) { var props = entityType.GetProperties(); var keyName = entityType.GetKeyName(); // 只更新:实体真实存在的普通字段(排除主键/集合导航/前端辅助字段) var safe = rawFields .Where(f => !string.IsNullOrWhiteSpace(f)) .Where(f => !f.Equals(keyName, StringComparison.OrdinalIgnoreCase)) .Where(f => !f.Equals("elementIndex", StringComparison.OrdinalIgnoreCase)) .Where(f => props.Any(p => p.Name == f && p.PropertyType.Name != "List`1")) .ToList(); return [.. safe]; } /// /// 明细表更新 /// /// /// public static void UpdateDetail(this EntityData entityData, BaseDbContext dbContext) { if (entityData.UpdateList == null) return; foreach (var obj in entityData.UpdateList) { var entry = dbContext.Entry(obj); entry.State = EntityState.Unchanged; foreach (var field in entityData.UpdateFields) { entry.Property(field).IsModified = true; } } } public static WebResponseContent ValidationDataVersion( this ServiceBase service, TEntity entity, SaveModel saveModel) where TEntity : BaseEntity where TRepository : IRepository { WebResponseContent webResponse = new(true); if (string.IsNullOrEmpty(saveModel.DataVersionField) || string.IsNullOrEmpty(saveModel.DataVersionValue)) return webResponse; var versionProperty = typeof(TEntity).GetProperty(saveModel.DataVersionField); if (versionProperty == null) return webResponse; var keyProperty = typeof(TEntity).GetKeyProperty(); object keyValue = keyProperty.GetValue(entity); var where = keyProperty.Name.CreateExpression(keyValue, LinqExpressionType.Equal); var selectExpression = saveModel.DataVersionField.GetExpression(); string dataVersionValue = service.repository.FindAsIQueryable(where).Select(selectExpression).FirstOrDefault(); if (string.IsNullOrEmpty(dataVersionValue)) return webResponse; if (dataVersionValue != saveModel.DataVersionValue) return webResponse.Error("数据已发生变化,请刷新页面后重新编辑"); string value = Guid.NewGuid().ToString(); versionProperty.SetValue(entity, value); saveModel.MainData[saveModel.DataVersionField] = value; return webResponse; } /// /// 获取更新前的原始数据 /// /// /// /// public static Expression> GetUpdateBeforeActionLogDbDataFilterExpression(this SaveModel saveDataModel) where TEntity : class { bool isActionLog = typeof(TEntity).IsTableActionLog(); if (!isActionLog) return null; var property = typeof(TEntity).GetKeyProperty(); object mainKeyVal = saveDataModel.MainData[property.Name]; Expression> expression = property.Name.CreateExpression(mainKeyVal.ToString(), LinqExpressionType.Equal); return expression; } /// /// 校验字段唯一 /// /// /// /// private static WebResponseContent ValidationEntityUnique(TEntity entity, bool isAdd) where TEntity : class { WebResponseContent webResponse = new WebResponseContent(); var uniqueFields = TableColumnContext.Data.Where(x => x.TableName == typeof(TEntity).Name && x.IsUnique == 1).Select(s => new { s.ColumnName, s.ColumnCnName }).ToList(); if (uniqueFields.Count == 0) { return webResponse.OK(); } foreach (var item in uniqueFields) { var property = typeof(TEntity).GetProperty(item.ColumnName); if (property == null) continue; string value = property.GetValue(entity)?.ToString(); if (value == null) continue; List searches = [ new SearchParameters() { Name=item.ColumnName, Value=value }, ]; if (!isAdd) { var keyProperty = typeof(TEntity).GetKeyProperty(); searches.Add(new SearchParameters() { Name = keyProperty.Name, Value = keyProperty.GetValue(entity).ToString(), DisplayType = "!=" }); } var param = new PageDataOptions() { Filter = searches, Page = 1, Rows = 1 }; if (param.GetSearchQueryable().Any()) { return webResponse.Error($"字段[{item.ColumnCnName}]值[{value}]已存在"); } } return webResponse.OK(); } public static Type[] GetDetailTypes() where T : class { return GetDetailTypes(typeof(T)); } public static Type[] GetDetailTypes(this Type mainType) { return mainType.GetCustomAttribute()?.DetailTable ?? []; ; } } }