mirror of
https://github.com/cq-panda/Vue.NetCore.git
synced 2026-10-19 06:58:16 +08:00
372 lines
16 KiB
C#
Executable File
372 lines
16 KiB
C#
Executable File
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<TEntity, TRepository>(
|
|
this SaveModel saveDataModel, ServiceBase<TEntity, TRepository> service)
|
|
where TEntity : BaseEntity where TRepository : IRepository<TEntity>
|
|
{
|
|
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<TEntity>()//审批字段默认值
|
|
.SetLogicDelValue<TEntity>() //设置默认创建人信息
|
|
.SetCreateDefaultVal(); //设置默认逻辑删除值
|
|
|
|
string validReslut = type.ValidateDicInEntity(saveDataModel.MainData, true, false, ApplicationServiceBaseConfig.UserIgnoreFields);
|
|
if (!string.IsNullOrEmpty(validReslut)) return (baseWebResponse.Error(validReslut), null);
|
|
|
|
//设置主键默认值
|
|
saveDataModel.MainData.SetPrimaryKeyDefaultValue<TEntity>();
|
|
//实体转换与租户设置
|
|
TEntity mainEntity = saveDataModel.MainData.DicToEntity<TEntity>();
|
|
|
|
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<TEntity, TRepository>(
|
|
this SaveModel saveDataModel, ServiceBase<TEntity, TRepository> service)
|
|
where TEntity : BaseEntity where TRepository : IRepository<TEntity>
|
|
{
|
|
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<TEntity>();
|
|
|
|
|
|
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<TEntity, TRepository>(
|
|
this SaveModel saveModel, ServiceBase<TEntity, TRepository> service,
|
|
TEntity mainEntity,
|
|
bool isAdd = true)
|
|
where TEntity : BaseEntity where TRepository : IRepository<TEntity>
|
|
{
|
|
service.MultipleTableEntity = new ApplicationServiceBaseMultipleTableEntity();
|
|
WebResponseContent webResponse = new(true);
|
|
var detailTypes = typeof(TEntity).GetCustomAttribute<EntityAttribute>().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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 明细表校验与转换
|
|
/// </summary>
|
|
/// <typeparam name="TMain"></typeparam>
|
|
/// <typeparam name="TDetail"></typeparam>
|
|
/// <param name="dic"></param>
|
|
/// <param name="delKeys"></param>
|
|
/// <returns></returns>
|
|
private static WebResponseContent ConvertDetailData<TMain, TDetail>(
|
|
TMain mainEntity,
|
|
SaveModel saveModel,
|
|
List<Dictionary<string, object>> dic,
|
|
List<object> 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<EntityAttribute>().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<TDetail> 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<TDetail>()
|
|
.SetCreateDefaultVal()
|
|
//设置自定义主表主键字段的值
|
|
.SetPrimaryKeyDefaultValue<TDetail>(foreignKey, mainKeyValue);
|
|
}
|
|
else
|
|
{
|
|
//记录编辑的字段
|
|
if (entityData.UpdateFields.Count == 0)
|
|
{
|
|
entityData.UpdateFields = [.. FilterUpdateFields(detailType, item.Select(s => s.Key))];
|
|
}
|
|
//编辑数据
|
|
item.SetModifyDefaultVal();
|
|
}
|
|
TDetail detailData = item.DicToEntity<TDetail>(); ;
|
|
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<string> 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];
|
|
}
|
|
/// <summary>
|
|
/// 明细表更新
|
|
/// </summary>
|
|
/// <param name="entityData"></param>
|
|
/// <param name="dbContext"></param>
|
|
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<TEntity, TRepository>(
|
|
this ServiceBase<TEntity, TRepository> service,
|
|
TEntity entity,
|
|
SaveModel saveModel)
|
|
where TEntity : BaseEntity where TRepository : IRepository<TEntity>
|
|
{
|
|
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<TEntity>(keyValue, LinqExpressionType.Equal);
|
|
var selectExpression = saveModel.DataVersionField.GetExpression<TEntity, string>();
|
|
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;
|
|
}
|
|
/// <summary>
|
|
/// 获取更新前的原始数据
|
|
/// </summary>
|
|
/// <typeparam name="TEntity"></typeparam>
|
|
/// <param name="saveDataModel"></param>
|
|
/// <returns></returns>
|
|
public static Expression<Func<TEntity, bool>> GetUpdateBeforeActionLogDbDataFilterExpression<TEntity>(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<Func<TEntity, bool>> expression = property.Name.CreateExpression<TEntity>(mainKeyVal.ToString(), LinqExpressionType.Equal);
|
|
return expression;
|
|
}
|
|
/// <summary>
|
|
/// 校验字段唯一
|
|
/// </summary>
|
|
/// <typeparam name="TEntity"></typeparam>
|
|
/// <param name="entity"></param>
|
|
/// <returns></returns>
|
|
private static WebResponseContent ValidationEntityUnique<TEntity>(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<SearchParameters> 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<TEntity>().Any())
|
|
{
|
|
return webResponse.Error($"字段[{item.ColumnCnName}]值[{value}]已存在");
|
|
}
|
|
}
|
|
return webResponse.OK();
|
|
}
|
|
|
|
public static Type[] GetDetailTypes<T>() where T : class
|
|
{
|
|
return GetDetailTypes(typeof(T));
|
|
}
|
|
|
|
|
|
public static Type[] GetDetailTypes(this Type mainType)
|
|
{
|
|
return mainType.GetCustomAttribute<EntityAttribute>()?.DetailTable ?? []; ;
|
|
}
|
|
}
|
|
}
|