using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text.Json.Serialization; using System.Threading.Tasks; using WalkingTec.Mvvm.Core.Extensions; using WalkingTec.Mvvm.Core.Support.FileHandlers; namespace WalkingTec.Mvvm.Core { /// /// 单表增删改查VM的接口 /// /// 继承TopBasePoco的类 public interface IBaseCRUDVM where T : TopBasePoco, new() { T Entity { get; } /// /// 根据主键Id获取Entity /// /// 主键Id void SetEntityById(object id); /// /// 设置Entity /// /// 要设定的TopBasePoco void SetEntity(object entity); /// /// 添加 /// void DoAdd(); Task DoAddAsync(); /// /// 修改 /// void DoEdit(bool updateAllFields); Task DoEditAsync(bool updateAllFields); /// /// 删除,对于TopBasePoco进行物理删除,对于PersistPoco把IsValid修改为false /// void DoDelete(); Task DoDeleteAsync(); /// /// 彻底删除,对PersistPoco进行物理删除 /// void DoRealDelete(); Task DoRealDeleteAsync(); /// /// 将源VM的上数据库上下文,Session,登录用户信息,模型状态信息,缓存信息等内容复制到本VM中 /// /// 复制的源 void CopyContext(BaseVM vm); /// /// 是否跳过基类的唯一性验证,批量导入的时候唯一性验证会由存储过程完成,不需要单独调用本类的验证方法 /// bool ByPassBaseValidation { get; set; } void Validate(); IModelStateService MSD { get; } } /// /// 单表增删改查基类,所有单表操作的VM应该继承这个基类 /// /// 继承TopBasePoco的类 public class BaseCRUDVM : BaseVM, IBaseCRUDVM where TModel : TopBasePoco, new() { public TModel Entity { get; set; } [JsonIgnore] public bool ByPassBaseValidation { get; set; } //保存读取时Include的内容 private List>> _toInclude { get; set; } /// /// 构造函数 /// public BaseCRUDVM() { //初始化Entity var ctor = typeof(TModel).GetConstructor(Type.EmptyTypes); Entity = ctor.Invoke(null) as TModel; //初始化VM中所有List<>的类 //var lists = typeof(TModel).GetAllProperties().Where(x => x.PropertyType.IsGeneric(typeof(List<>))); //foreach (var li in lists) //{ // var gs = li.PropertyType.GetGenericArguments(); // var newObj = Activator.CreateInstance(typeof(List<>).MakeGenericType(gs[0])); // li.SetValue(Entity, newObj, null); //} } public IQueryable GetBaseQuery() { return DC.Set(); } /// /// 设定添加和修改时对于重复数据的判断,子类进行相关操作时应重载这个函数 /// /// 唯一性属性 public virtual DuplicatedInfo SetDuplicatedCheck() { return null; } /// /// 设定读取是Include的内容 /// /// 需要关联的类 public void SetInclude(params Expression>[] exps) { _toInclude = _toInclude ?? new List>>(); _toInclude.AddRange(exps); } /// /// 根据主键Id设定Entity /// /// 主键Id public void SetEntityById(object id) { this.Entity = GetById(id); } /// /// 设置Entity /// /// 要设定的TopBasePoco public void SetEntity(object entity) { this.Entity = entity as TModel; } /// /// 根据主键获取Entity /// /// 主键Id /// Entity protected virtual TModel GetById(object Id) { TModel rv = null; //建立基础查询 var query = DC.Set().AsQueryable(); //循环添加其他设定的Include if (_toInclude != null) { foreach (var item in _toInclude) { query = query.Include(item); } } if (typeof(IPersistPoco).IsAssignableFrom(typeof(TModel))) { var mod = new IsValidModifier(); var newExp = mod.Modify(query.Expression); query = query.Provider.CreateQuery(newExp) as IOrderedQueryable; } //获取数据 rv = query.CheckID(Id).AsNoTracking().SingleOrDefault(); if (rv == null) { throw new Exception("数据不存在"); } //如果TopBasePoco有关联的附件,则自动Include 附件名称 var pros = typeof(TModel).GetAllProperties(); var fa = pros.Where(x => x.PropertyType == typeof(FileAttachment)).ToList(); foreach (var f in fa) { var fname = DC.GetFKName2(f.Name); var fid = typeof(TModel).GetSingleProperty(fname).GetValue(rv); if (fid != null && Wtm.ServiceProvider != null) { var fp = Wtm.ServiceProvider.GetRequiredService(); var file = fp.GetFile(fid?.ToString(), false, DC); rv.SetPropertyValue(f.Name, file); } } return rv; } /// /// 添加,进行默认的添加操作。子类如有自定义操作应重载本函数 /// public virtual void DoAdd() { DoAddPrepare(); //删除不需要的附件 if (DeletedFileIds != null && DeletedFileIds.Count > 0 && Wtm.ServiceProvider != null) { var fp = Wtm.ServiceProvider.GetRequiredService(); foreach (var item in DeletedFileIds) { fp.DeleteFile(item.ToString(), DC); } } DC.SaveChanges(); } public virtual async Task DoAddAsync() { DoAddPrepare(); //删除不需要的附件 if (DeletedFileIds != null && DeletedFileIds.Count > 0 && Wtm.ServiceProvider != null) { var fp = Wtm.ServiceProvider.GetRequiredService(); foreach (var item in DeletedFileIds) { fp.DeleteFile(item.ToString(), DC.ReCreate()); } } await DC.SaveChangesAsync(); } private void DoAddPrepare() { var pros = typeof(TModel).GetAllProperties(); //将所有TopBasePoco的属性赋空值,防止添加关联的重复内容 if (typeof(TModel) != typeof(FileAttachment)) { foreach (var pro in pros) { if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBasePoco))) { pro.SetValue(Entity, null); } } } //自动设定添加日期和添加人 if (typeof(IBasePoco).IsAssignableFrom(typeof(TModel))) { IBasePoco ent = Entity as IBasePoco; if (ent.CreateTime == null) { ent.CreateTime = DateTime.Now; } if (string.IsNullOrEmpty(ent.CreateBy)) { ent.CreateBy = LoginUserInfo?.ITCode; } } if (typeof(IPersistPoco).IsAssignableFrom(typeof(TModel))) { (Entity as IPersistPoco).IsValid = true; } #region 更新子表 foreach (var pro in pros) { //找到类型为List的字段 if (pro.PropertyType.GenericTypeArguments.Count() > 0) { //获取xxx的类型 var ftype = pro.PropertyType.GenericTypeArguments.First(); //如果xxx继承自TopBasePoco if (ftype.IsSubclassOf(typeof(TopBasePoco))) { //界面传过来的子表数据 IEnumerable list = pro.GetValue(Entity) as IEnumerable; if (list != null && list.Count() > 0) { string fkname = DC.GetFKName(pro.Name); var itemPros = ftype.GetAllProperties(); bool found = false; foreach (var newitem in list) { foreach (var itempro in itemPros) { if (itempro.PropertyType.IsSubclassOf(typeof(TopBasePoco))) { itempro.SetValue(newitem, null); } if (!string.IsNullOrEmpty(fkname)) { if (itempro.Name.ToLower() == fkname.ToLower()) { try { itempro.SetValue(newitem, Entity.GetID()); found = true; } catch { } } } } } //如果没有找到相应的外建字段,则可能是多对多的关系,或者做了特殊的设定,这种情况框架无法支持,直接退出本次循环 if (found == false) { continue; } //循环页面传过来的子表数据,自动设定添加日期和添加人 foreach (var newitem in list) { var subtype = newitem.GetType(); if (typeof(IBasePoco).IsAssignableFrom(subtype)) { IBasePoco ent = newitem as IBasePoco; if (ent.CreateTime == null) { ent.CreateTime = DateTime.Now; } if (string.IsNullOrEmpty(ent.CreateBy)) { ent.CreateBy = LoginUserInfo?.ITCode; } } } } } } } #endregion //添加数据 DC.Set().Add(Entity); } /// /// 修改,进行默认的修改操作。子类如有自定义操作应重载本函数 /// /// 为true时,框架会更新当前Entity的全部值,为false时,框架会检查Request.Form里的key,只更新表单提交的字段 public virtual void DoEdit(bool updateAllFields = false) { DoEditPrepare(updateAllFields); try { DC.SaveChanges(); } catch { MSD.AddModelError(" ", Localizer["Sys.EditFailed"]); } //删除不需要的附件 if (DeletedFileIds != null && DeletedFileIds.Count > 0 && Wtm.ServiceProvider != null) { var fp = Wtm.ServiceProvider.GetRequiredService(); foreach (var item in DeletedFileIds) { fp.DeleteFile(item.ToString(), DC.ReCreate()); } } } public virtual async Task DoEditAsync(bool updateAllFields = false) { DoEditPrepare(updateAllFields); await DC.SaveChangesAsync(); //删除不需要的附件 if (DeletedFileIds != null && DeletedFileIds.Count > 0 && Wtm.ServiceProvider != null) { var fp = Wtm.ServiceProvider.GetRequiredService(); foreach (var item in DeletedFileIds) { fp.DeleteFile(item.ToString(), DC); } } } private void DoEditPrepare(bool updateAllFields) { if (typeof(IBasePoco).IsAssignableFrom(typeof(TModel))) { IBasePoco ent = Entity as IBasePoco; //if (ent.UpdateTime == null) //{ ent.UpdateTime = DateTime.Now; //} //if (string.IsNullOrEmpty(ent.UpdateBy)) //{ ent.UpdateBy = LoginUserInfo?.ITCode; //} } var pros = typeof(TModel).GetAllProperties(); pros = pros.Where(x => x.CustomAttributes.Any(y => y.AttributeType == typeof(NotMappedAttribute)) == false).ToList(); if (typeof(TModel) != typeof(FileAttachment)) { foreach (var pro in pros) { if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBasePoco))) { pro.SetValue(Entity, null); } } } #region 更新子表 foreach (var pro in pros) { //找到类型为List的字段 if (pro.PropertyType.GenericTypeArguments.Count() > 0) { //获取xxx的类型 var ftype = pro.PropertyType.GenericTypeArguments.First(); //如果xxx继承自TopBasePoco if (ftype.IsSubclassOf(typeof(TopBasePoco))) { //界面传过来的子表数据 if (pro.GetValue(Entity) is IEnumerable list && list.Count() > 0) { //获取外键字段名称 string fkname = DC.GetFKName(pro.Name); var itemPros = ftype.GetAllProperties(); bool found = false; foreach (var newitem in list) { var subtype = newitem.GetType(); if (typeof(IBasePoco).IsAssignableFrom(subtype)) { IBasePoco ent = newitem as IBasePoco; if (ent.UpdateTime == null) { ent.UpdateTime = DateTime.Now; } if (string.IsNullOrEmpty(ent.UpdateBy)) { ent.UpdateBy = LoginUserInfo?.ITCode; } } //循环页面传过来的子表数据,将关联到TopBasePoco的字段设为null,并且把外键字段的值设定为主表ID foreach (var itempro in itemPros) { if (itempro.PropertyType.IsSubclassOf(typeof(TopBasePoco))) { itempro.SetValue(newitem, null); } if (!string.IsNullOrEmpty(fkname)) { if (itempro.Name.ToLower() == fkname.ToLower()) { itempro.SetValue(newitem, Entity.GetID()); found = true; } } } } //如果没有找到相应的外建字段,则可能是多对多的关系,或者做了特殊的设定,这种情况框架无法支持,直接退出本次循环 if (found == false) { continue; } TModel _entity = null; //打开新的数据库联接,获取数据库中的主表和子表数据 //using (var ndc = DC.CreateNew()) //{ _entity = DC.Set().Include(pro.Name).AsNoTracking().CheckID(Entity.GetID()).FirstOrDefault(); //} if (_entity == null) { MSD.AddModelError(" ", Localizer["Sys.EditFailed"]); return; } //比较子表原数据和新数据的区别 IEnumerable toadd = null; IEnumerable toremove = null; IEnumerable data = _entity.GetType().GetSingleProperty(pro.Name).GetValue(_entity) as IEnumerable; Utils.CheckDifference(data, list, out toremove, out toadd); //设定子表应该更新的字段 List setnames = new List(); foreach (var field in FC.Keys) { var f = field.ToLower(); if (f.StartsWith("entity." + pro.Name.ToLower() + "[0].")) { string name = f.Replace("entity." + pro.Name.ToLower() + "[0].", ""); setnames.Add(name); } } //前台传过来的数据 foreach (var newitem in list) { //数据库中的数据 foreach (var item in data) { //需要更新的数据 if (newitem.GetID().ToString() == item.GetID().ToString()) { dynamic i = newitem; var newitemType = item.GetType(); foreach (var itempro in itemPros) { if (!itempro.PropertyType.IsSubclassOf(typeof(TopBasePoco)) && (updateAllFields == true || setnames.Contains(itempro.Name.ToLower()))) { var notmapped = itempro.GetCustomAttribute(); if (itempro.Name != "ID" && notmapped == null && itempro.PropertyType.IsList() == false) { DC.UpdateProperty(i, itempro.Name); } } } if (typeof(IBasePoco).IsAssignableFrom(item.GetType())) { DC.UpdateProperty(i, "UpdateTime"); DC.UpdateProperty(i, "UpdateBy"); } } } } //需要删除的数据 foreach (var item in toremove) { //如果是PersistPoco,则把IsValid设为false,并不进行物理删除 if (typeof(IPersistPoco).IsAssignableFrom(ftype)) { (item as IPersistPoco).IsValid = false; if (typeof(IBasePoco).IsAssignableFrom(ftype)) { (item as IBasePoco).UpdateTime = DateTime.Now; (item as IBasePoco).UpdateBy = LoginUserInfo?.ITCode; } dynamic i = item; DC.UpdateEntity(i); } else { foreach (var itempro in itemPros) { if (itempro.PropertyType.IsSubclassOf(typeof(TopBasePoco))) { itempro.SetValue(item, null); } } dynamic i = item; DC.DeleteEntity(i); } } //需要添加的数据 foreach (var item in toadd) { if (typeof(IBasePoco).IsAssignableFrom(item.GetType())) { IBasePoco ent = item as IBasePoco; if (ent.CreateTime == null) { ent.CreateTime = DateTime.Now; } if (string.IsNullOrEmpty(ent.CreateBy)) { ent.CreateBy = LoginUserInfo?.ITCode; } } DC.AddEntity(item); } } else if ((pro.GetValue(Entity) is IEnumerable list2 && list2?.Count() == 0)) { var itemPros = ftype.GetAllProperties(); var _entity = DC.Set().Include(pro.Name).AsNoTracking().CheckID(Entity.GetID()).FirstOrDefault(); if (_entity != null) { IEnumerable removeData = _entity.GetType().GetSingleProperty(pro.Name).GetValue(_entity) as IEnumerable; //如果是PersistPoco,则把IsValid设为false,并不进行物理删除 if (removeData is IEnumerable removePersistPocoData) { foreach (var item in removePersistPocoData) { (item as IPersistPoco).IsValid = false; if (typeof(IBasePoco).IsAssignableFrom(item.GetType())) { (item as IBasePoco).UpdateTime = DateTime.Now; (item as IBasePoco).UpdateBy = LoginUserInfo?.ITCode; } dynamic i = item; DC.UpdateEntity(i); } } else { foreach (var item in removeData) { foreach (var itempro in itemPros) { if (itempro.PropertyType.IsSubclassOf(typeof(TopBasePoco))) { itempro.SetValue(item, null); } } dynamic i = item; DC.DeleteEntity(i); } } } } } } } #endregion if (updateAllFields == false) { foreach (var field in FC.Keys) { var f = field.ToLower(); if (f.StartsWith("entity.") && !f.Contains("[")) { string name = f.Replace("entity.", ""); try { DC.UpdateProperty(Entity, pros.Where(x => name!="id" && x.Name.ToLower() == name).Select(x => x.Name).FirstOrDefault());//id字段不可修改 } catch (Exception ex) { MSD.AddModelError("", CoreProgram._localizer?["Sys.EditPrepare"]); } } } if (typeof(IBasePoco).IsAssignableFrom(typeof(TModel))) { try { DC.UpdateProperty(Entity, "UpdateTime"); DC.UpdateProperty(Entity, "UpdateBy"); } catch (Exception) { } } } else { DC.UpdateEntity(Entity); } } /// /// 删除,进行默认的删除操作。子类如有自定义操作应重载本函数 /// public virtual void DoDelete() { //如果是PersistPoco,则把IsValid设为false,并不进行物理删除 if (typeof(IPersistPoco).IsAssignableFrom(typeof(TModel))) { FC.Add("Entity.IsValid", 0); (Entity as IPersistPoco).IsValid = false; var pros = typeof(TModel).GetAllProperties(); //如果包含List,将子表IsValid也设置为false var fas = pros.Where(x => typeof(IEnumerable).IsAssignableFrom(x.PropertyType)).ToList(); foreach (var f in fas) { f.SetValue(Entity, f.PropertyType.GetConstructor(Type.EmptyTypes).Invoke(null)); } DoEditPrepare(false); DC.SaveChanges(); } //如果是普通的TopBasePoco,则进行物理删除 else if (typeof(TModel).GetTypeInfo().IsSubclassOf(typeof(TopBasePoco))) { DoRealDelete(); } } public virtual async Task DoDeleteAsync() { //如果是PersistPoco,则把IsValid设为false,并不进行物理删除 if (typeof(IPersistPoco).IsAssignableFrom(typeof(TModel))) { FC.Add("Entity.IsValid", 0); (Entity as IPersistPoco).IsValid = false; var pros = typeof(TModel).GetAllProperties(); //如果包含List,将子表IsValid也设置为false var fas = pros.Where(x => typeof(IEnumerable).IsAssignableFrom(x.PropertyType)).ToList(); foreach (var f in fas) { f.SetValue(Entity, f.PropertyType.GetConstructor(Type.EmptyTypes).Invoke(null)); } fas = pros.Where(x => typeof(TopBasePoco).IsAssignableFrom(x.PropertyType)).ToList(); foreach (var f in fas) { f.SetValue(Entity, null); } DoEditPrepare(false); try { await DC.SaveChangesAsync(); } catch (DbUpdateException) { MSD.AddModelError("", CoreProgram._localizer?["Sys.DeleteFailed"]); } } //如果是普通的TopBasePoco,则进行物理删除 else if (typeof(TModel).GetTypeInfo().IsSubclassOf(typeof(TopBasePoco))) { DoRealDelete(); } } /// /// 物理删除,对于普通的TopBasePoco和Delete操作相同,对于PersistPoco则进行真正的删除。子类如有自定义操作应重载本函数 /// public virtual void DoRealDelete() { try { List fileids = new List(); var pros = typeof(TModel).GetAllProperties(); //如果包含附件,则先删除附件 var fa = pros.Where(x => x.PropertyType == typeof(FileAttachment) || typeof(TopBasePoco).IsAssignableFrom(x.PropertyType)).ToList(); foreach (var f in fa) { if (f.GetValue(Entity) is FileAttachment file) { fileids.Add(file.ID); } f.SetValue(Entity, null); } var fas = pros.Where(x => typeof(IEnumerable).IsAssignableFrom(x.PropertyType)).ToList(); foreach (var f in fas) { var subs = f.GetValue(Entity) as IEnumerable; if (subs == null) { var fullEntity = DC.Set().AsQueryable().Include(f.Name).AsNoTracking().CheckID(Entity.ID).FirstOrDefault(); subs = f.GetValue(fullEntity) as IEnumerable; } if (subs != null) { foreach (var sub in subs) { fileids.Add(sub.FileId); } f.SetValue(Entity, null); } } if (typeof(TModel) != typeof(FileAttachment)) { foreach (var pro in pros) { if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBasePoco))) { pro.SetValue(Entity, null); } } } DC.DeleteEntity(Entity); DC.SaveChanges(); if (Wtm.ServiceProvider != null) { var fp = Wtm.ServiceProvider.GetRequiredService(); foreach (var item in fileids) { fp.DeleteFile(item.ToString(), DC.ReCreate()); } } } catch (Exception) { MSD.AddModelError("", CoreProgram._localizer?["Sys.DeleteFailed"]); } } public virtual async Task DoRealDeleteAsync() { try { List fileids = new List(); var pros = typeof(TModel).GetAllProperties(); //如果包含附件,则先删除附件 var fa = pros.Where(x => x.PropertyType == typeof(FileAttachment) || typeof(TopBasePoco).IsAssignableFrom(x.PropertyType)).ToList(); foreach (var f in fa) { if (f.GetValue(Entity) is FileAttachment file) { fileids.Add(file.ID); } f.SetValue(Entity, null); } var fas = pros.Where(x => typeof(IEnumerable).IsAssignableFrom(x.PropertyType)).ToList(); foreach (var f in fas) { var subs = f.GetValue(Entity) as IEnumerable; foreach (var sub in subs) { fileids.Add(sub.FileId); } f.SetValue(Entity, null); } if (typeof(TModel) != typeof(FileAttachment)) { foreach (var pro in pros) { if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBasePoco))) { pro.SetValue(Entity, null); } } } DC.DeleteEntity(Entity); await DC.SaveChangesAsync(); if (Wtm.ServiceProvider != null) { var fp = Wtm.ServiceProvider.GetRequiredService(); foreach (var item in fileids) { fp.DeleteFile(item.ToString(), DC.ReCreate()); } } } catch (Exception) { MSD.AddModelError("", CoreProgram._localizer?["Sys.DeleteFailed"]); } } /// /// 创建重复数据信息 /// /// 重复数据信息 /// 重复数据信息 protected DuplicatedInfo CreateFieldsInfo(params DuplicatedField[] FieldExps) { DuplicatedInfo d = new DuplicatedInfo(); d.AddGroup(FieldExps); return d; } /// /// 创建一个简单重复数据信息 /// /// 重复数据的字段 /// 重复数据信息 public static DuplicatedField SimpleField(Expression> FieldExp) { return new DuplicatedField(FieldExp); } /// /// 创建一个关联到其他表数组中数据的重复信息 /// /// 关联表类 /// 指向关联表类数组的Lambda /// 指向最终字段的Lambda /// 重复数据信息 public static DuplicatedField SubField(Expression>> MiddleExp, params Expression>[] FieldExps) { return new ComplexDuplicatedField(MiddleExp, FieldExps); } /// /// 验证数据,默认验证重复数据。子类如需要其他自定义验证,则重载这个函数 /// /// 验证结果 public override void Validate() { if (ByPassBaseValidation == false) { base.Validate(); ////如果msd是BasicMSD,则认为他是手动创建的,也就是说并没有走asp.net core默认的模型验证 ////那么手动验证模型 //if (Wtm?.MSD is BasicMSD) //{ // var valContext = new ValidationContext(this.Entity); // List error = new List(); // if (!Validator.TryValidateObject(Entity, valContext, error, true)) // { // foreach (var item in error) // { // string key = item.MemberNames.FirstOrDefault(); // if (MSD.Keys.Contains(key) == false) // { // MSD.AddModelError($"Entity.{key}", item.ErrorMessage); // } // } // } // var list = typeof(TModel).GetAllProperties().Where(x => x.PropertyType.IsListOf()); // foreach (var item in list) // { // var it = item.GetValue(Entity) as IEnumerable; // if(it == null) // { // continue; // } // var contextset = false; // foreach (var e in it) // { // if(contextset == false) // { // valContext = new ValidationContext(e); // contextset = true; // } // if (!Validator.TryValidateObject(e, valContext, error, true)) // { // foreach (var err in error) // { // string key = err.MemberNames.FirstOrDefault(); // if (MSD.Keys.Contains(key) == false) // { // MSD.AddModelError($"Entity.{item.Name}.{key}", err.ErrorMessage); // } // } // } // } // } //} //验证重复数据 ValidateDuplicateData(); } } /// /// 验证重复数据 /// 如果存在重复的数据,则返回已存在数据的id列表 /// 如果不存在重复数据,则返回一个空列表 /// protected List ValidateDuplicateData() { //定义一个对象列表用于存放重复数据的id var count = new List(); //获取设定的重复字段信息 var checkCondition = SetDuplicatedCheck(); if (checkCondition != null && checkCondition.Groups.Count > 0) { //生成基础Query var baseExp = DC.Set().AsQueryable(); var modelType = typeof(TModel); ParameterExpression para = Expression.Parameter(modelType, "tm"); //循环所有重复字段组 foreach (var group in checkCondition.Groups) { var innercount = new List(); List conditions = new List(); //生成一个表达式,类似于 x=>x.Id != id,这是为了当修改数据时验证重复性的时候,排除当前正在修改的数据 var idproperty = typeof(TModel).GetSingleProperty("ID"); MemberExpression idLeft = Expression.Property(para, idproperty); ConstantExpression idRight = Expression.Constant(Entity.GetID()); BinaryExpression idNotEqual = Expression.NotEqual(idLeft, idRight); conditions.Add(idNotEqual); List props = new List(); //在每个组中循环所有字段 foreach (var field in group.Fields) { Expression exp = field.GetExpression(Entity, para); if (exp != null) { conditions.Add(exp); } //将字段名保存,为后面生成错误信息作准备 props.AddRange(field.GetProperties()); } //如果要求判断id不重复,则去掉id不相等的判断,加入id相等的判断 if (props.Any(x => x.Name.ToLower() == "id")) { conditions.RemoveAt(0); BinaryExpression idEqual = Expression.Equal(idLeft, idRight); conditions.Insert(0, idEqual); } //int count = 0; if (conditions.Count > 1) { //循环添加条件并生成Where语句 //Expression conExp = conditions[0]; Expression whereCallExpression = baseExp.Expression; for (int i = 0; i < conditions.Count; i++) { whereCallExpression = Expression.Call( typeof(Queryable), "Where", new Type[] { modelType }, whereCallExpression, Expression.Lambda>(conditions[i], new ParameterExpression[] { para })); } var result = baseExp.Provider.CreateQuery(whereCallExpression); foreach (TopBasePoco res in result) { var id = res.GetID(); count.Add(id); innercount.Add(id); } } if (innercount.Count > 0) { //循环拼接所有字段名 string AllName = ""; foreach (var prop in props) { string name = PropertyHelper.GetPropertyDisplayName(prop); AllName += name + ","; } if (AllName.EndsWith(",")) { AllName = AllName.Remove(AllName.Length - 1); } //如果只有一个字段重复,则拼接形成 xxx字段重复 这种提示 if (props.Count == 1) { MSD.AddModelError(GetValidationFieldName(props[0])[0], CoreProgram._localizer?["Sys.DuplicateError", AllName]); } //如果多个字段重复,则拼接形成 xx,yy,zz组合字段重复 这种提示 else if (props.Count > 1) { MSD.AddModelError(GetValidationFieldName(props.First())[0], CoreProgram._localizer?["Sys.DuplicateGroupError", AllName]); } } } } return count; } /// /// 根据属性信息获取验证字段名 /// /// 属性信息 /// 验证字段名称数组,用于ValidationResult private string[] GetValidationFieldName(PropertyInfo pi) { return new[] { "Entity." + pi.Name }; } } }