| using SqlSugar; | 
| 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; | 
| using System.Threading.Tasks; | 
| using WIDESEA_Core.Const; | 
| using WIDESEA_Core.Enums; | 
| using WIDESEA_Core.Helper; | 
|   | 
| namespace WIDESEA_Core.Utilities | 
| { | 
|     public static class EntityProperties | 
|     { | 
|         /// <summary> | 
|         /// 验证数据库字段类型与值是否正确, | 
|         /// </summary> | 
|         /// <param name="value">值</param> | 
|         /// <param name="propertyInfo">要验证的类的属性,若不为null,则会判断字符串的长度是否正确</param> | 
|         /// <returns>(bool, string, object)bool成否校验成功,string校验失败信息,object,当前校验的值</returns> | 
|         public static (bool, string, object) ValidationVal(this PropertyInfo propertyInfo, object value) | 
|         { | 
|             string dbType = ""; | 
|             SugarColumn sugarColumn = null; | 
|             if (propertyInfo != null) | 
|             { | 
|                 sugarColumn = propertyInfo.GetCustomAttribute<SugarColumn>(); | 
|                 dbType = propertyInfo.PropertyType != null ? propertyInfo.GetProperWithDbType() : SqlDbTypeName.NVarChar; | 
|             } | 
|             dbType = dbType.ToLower(); | 
|             string val = value?.ToString(); | 
|             //验证长度 | 
|             string reslutMsg = string.Empty; | 
|             if (dbType == SqlDbTypeName.Int) | 
|             { | 
|                 if (!value.IsInt()) | 
|                     reslutMsg = "只能为有效整数"; | 
|             }  //2021.10.12增加属性校验long类型的支持 | 
|             else if (dbType == SqlDbTypeName.BigInt) | 
|             { | 
|                 if (!long.TryParse(val, out _)) | 
|                 { | 
|                     reslutMsg = "只能为有效整数"; | 
|                 } | 
|             } | 
|             else if (dbType == SqlDbTypeName.DateTime | 
|                 || dbType == SqlDbTypeName.Date | 
|                 || dbType == SqlDbTypeName.SmallDateTime | 
|                 || dbType == SqlDbTypeName.SmallDate | 
|                 ) | 
|             { | 
|                 if (!value.IsDate()) | 
|                     reslutMsg = "必须为日期格式"; | 
|             } | 
|             else if (dbType == SqlDbTypeName.Float || dbType == SqlDbTypeName.Decimal || dbType == SqlDbTypeName.Double) | 
|             { | 
|   | 
|                 if (!val.IsNumber(null)) | 
|                 { | 
|                     reslutMsg = "不是有效数字"; | 
|                 } | 
|             } | 
|             else if (dbType == SqlDbTypeName.UniqueIdentifier) | 
|             { | 
|                 if (!val.IsGuid()) | 
|                 { | 
|                     reslutMsg = propertyInfo.Name + "Guid不正确"; | 
|                 } | 
|             } | 
|             else if (propertyInfo != null | 
|                 && (dbType == SqlDbTypeName.VarChar | 
|                 || dbType == SqlDbTypeName.NVarChar | 
|                 || dbType == SqlDbTypeName.NChar | 
|                 || dbType == SqlDbTypeName.Char | 
|                 || dbType == SqlDbTypeName.Text)) | 
|             { | 
|   | 
|                 //默认nvarchar(max) 、text 长度不能超过20000 | 
|                 if (val.Length > 200000) | 
|                 { | 
|                     reslutMsg = $"字符长度最多【200000】"; | 
|                 } | 
|                 else | 
|                 { | 
|   | 
|                     int length = sugarColumn.Length; | 
|                     if (length == 0) { return (true, null, value); } | 
|                     //判断双字节与单字段 | 
|                     else if (length < 8000 && | 
|                         ((dbType.Substring(0, 1) != "n" | 
|                         && Encoding.UTF8.GetBytes(val.ToCharArray()).Length > length) | 
|                          || val.Length > length) | 
|                          ) | 
|                     { | 
|                         reslutMsg = $"最多只能【{length}】个字符。"; | 
|                     } | 
|                 } | 
|             } | 
|             if (!string.IsNullOrEmpty(reslutMsg) && propertyInfo != null) | 
|             { | 
|                 reslutMsg = sugarColumn.ColumnDescription + reslutMsg; | 
|             } | 
|             return (reslutMsg == "" ? true : false, reslutMsg, value); | 
|         } | 
|   | 
|         public static List<(bool, string, object)> ValidationValueForDbType(this PropertyInfo propertyInfo, params object[] values) | 
|         { | 
|             List<(bool, string, object)> result = new List<(bool, string, object)>(); | 
|             foreach (object value in values) | 
|             { | 
|                 result.Add(propertyInfo.ValidationVal(value)); | 
|             } | 
|             return result; | 
|         } | 
|   | 
|         private static readonly Dictionary<Type, string> ProperWithDbType = new Dictionary<Type, string>() { | 
|             {  typeof(string),SqlDbTypeName.NVarChar }, | 
|             { typeof(DateTime),SqlDbTypeName.DateTime}, | 
|             {typeof(long),SqlDbTypeName.BigInt }, | 
|             {typeof(int),SqlDbTypeName.Int}, | 
|             { typeof(decimal),SqlDbTypeName.Decimal }, | 
|             { typeof(float),SqlDbTypeName.Float }, | 
|             { typeof(double),SqlDbTypeName.Double }, | 
|             {  typeof(byte),SqlDbTypeName.Int },//类型待完 | 
|             { typeof(Guid),SqlDbTypeName.UniqueIdentifier} | 
|         }; | 
|   | 
|         public static string GetProperWithDbType(this PropertyInfo propertyInfo) | 
|         { | 
|             bool result = ProperWithDbType.TryGetValue(propertyInfo.PropertyType, out string value); | 
|             if (result) | 
|             { | 
|                 return value; | 
|             } | 
|             return SqlDbTypeName.NVarChar; | 
|         } | 
|   | 
|         /// <summary> | 
|         /// 判断hash的列是否为对应的实体,并且值是否有效 | 
|         /// </summary> | 
|         /// <param name="typeinfo"></param> | 
|         /// <param name="dic"></param> | 
|         /// <param name="removeNotContains">移除不存在字段</param> | 
|         /// <param name="removerKey">移除主键</param> | 
|         /// <returns></returns> | 
|         public static string ValidateDicInEntity(this Type typeinfo, Dictionary<string, object> dic, bool removerKey, PropertyInfo[] propertyInfo, string[]? ignoreFields = null) | 
|         { | 
|             if (dic == null || dic.Count == 0) { return "参数无效"; } | 
|   | 
|             // 不存在的字段直接移除 | 
|             dic.Where(x => !propertyInfo.Any(p => p.Name == x.Key.FirstLetterToUpper())).Select(s => s.Key).ToList().ForEach(f => | 
|             { | 
|                 dic.Remove(f); | 
|             }); | 
|   | 
|             string keyName = typeinfo.GetKeyName(); | 
|             //移除主键 | 
|             if (removerKey) | 
|                 dic.Remove(keyName); | 
|             //else | 
|             //{ | 
|             //    if (!dic.ContainsKey(keyName)) | 
|             //        return "请传入主键参数"; | 
|             //} | 
|   | 
|             foreach (PropertyInfo property in propertyInfo) | 
|             { | 
|                 SugarColumn? sugarColumn = property.GetCustomAttribute<SugarColumn>(); | 
|                 if (sugarColumn == null) | 
|                 { | 
|                     Navigate? navigate = property.GetCustomAttribute<Navigate>(); | 
|                     if(navigate != null) | 
|                     { | 
|                         continue; | 
|                     } | 
|                     return "请配置SugarColumn属性"; | 
|                 } | 
|                      | 
|                 //忽略与主键的字段不做验证 | 
|                 if (property.Name == keyName.FirstLetterToUpper() || (ignoreFields != null && ignoreFields.Contains(property.Name)) || sugarColumn.IsOnlyIgnoreInsert || sugarColumn.IsOnlyIgnoreUpdate || sugarColumn.IsIgnore) | 
|                     continue; | 
|   | 
|                 //不在编辑中的列,是否也要必填 | 
|                 if (!dic.ContainsKey(property.Name.FirstLetterToLower())) | 
|                 { | 
|                     if (!sugarColumn.IsNullable) | 
|                     { | 
|                         if (sugarColumn.DefaultValue == null) | 
|                             return sugarColumn.ColumnDescription + "为必须提交项"; | 
|                         continue; | 
|                     } | 
|                     continue; | 
|                 } | 
|                 if(dic[property.Name.FirstLetterToLower()] != null) | 
|                 { | 
|                     string str = dic[property.Name.FirstLetterToLower()].ToString(); | 
|                     //将所有空值设置为null | 
|                     if (str == string.Empty) | 
|                         dic[property.Name.FirstLetterToLower()] = null; | 
|                 } | 
|                  | 
|             } | 
|             return string.Empty; | 
|         } | 
|   | 
|         public static string ValidateDicInEntity(this Type typeinfo, List<Dictionary<string, object>> dicList, bool removerKey, string[] ignoreFields = null) | 
|         { | 
|             PropertyInfo[] propertyInfo = typeinfo.GetProperties(); | 
|             string reslutMsg = string.Empty; | 
|             foreach (Dictionary<string, object> dic in dicList) | 
|             { | 
|                 reslutMsg = typeinfo.ValidateDicInEntity(dic, removerKey, propertyInfo, ignoreFields); | 
|                 if (!string.IsNullOrEmpty(reslutMsg)) | 
|                     return reslutMsg; | 
|             } | 
|             return reslutMsg; | 
|         } | 
|   | 
|         public static string GetKeyName(this Type typeinfo) | 
|         { | 
|             return typeinfo.GetProperties().GetKeyName(); | 
|         } | 
|   | 
|         public static string GetKeyName(this PropertyInfo[] properties) | 
|         { | 
|             foreach (PropertyInfo property in properties) | 
|             { | 
|                 SugarColumn? sugarColumn = property.GetCustomAttribute<SugarColumn>(); | 
|                 if (sugarColumn != null) | 
|                 { | 
|                     if (sugarColumn.IsPrimaryKey) | 
|                         return property.Name; | 
|                 } | 
|             } | 
|             return null; | 
|         } | 
|   | 
|         public static PropertyInfo GetKeyProperty(this Type typeinfo) | 
|         { | 
|             PropertyInfo[] properties = typeinfo.GetProperties(); | 
|             foreach (PropertyInfo property in properties) | 
|             { | 
|                 SugarColumn sugarColumn = property.GetCustomAttribute<SugarColumn>(); | 
|                 if (sugarColumn?.IsPrimaryKey ?? false) | 
|                 { | 
|                     return property; | 
|                 } | 
|             } | 
|             return null; | 
|         } | 
|   | 
|         public static Type GetDetailType(this Type typeinfo) | 
|         { | 
|             PropertyInfo[] properties = typeinfo.GetProperties(); | 
|             foreach (PropertyInfo property in properties) | 
|             { | 
|                 Navigate? navigate = property.GetCustomAttribute<Navigate>(); | 
|                 if (navigate is not null) | 
|                 { | 
|                     if (navigate.GetNavigateType() == NavigateType.OneToOne) | 
|                         return property.PropertyType; | 
|                     else | 
|                         return property.PropertyType.GenericTypeArguments[0]; | 
|                 } | 
|             } | 
|             return null; | 
|         } | 
|   | 
|         public static string GetMainIdByDetail(this Type typeinfo) | 
|         { | 
|             PropertyInfo[] properties = typeinfo.GetProperties(); | 
|             foreach (PropertyInfo property in properties) | 
|             { | 
|                 Navigate? navigate = property.GetCustomAttribute<Navigate>(); | 
|                 if (navigate is not null) | 
|                 { | 
|                     return navigate.GetName(); | 
|                 } | 
|             } | 
|             return null; | 
|         } | 
|   | 
|         public static void SetDetailId<T>(this Type typeinfo, T enetiy, object id, string name) | 
|         { | 
|             PropertyInfo property = typeinfo.GetProperty(name); | 
|             if (property != null) | 
|             { | 
|                 property.SetValue(enetiy, id); | 
|             } | 
|         } | 
|   | 
|         public static PropertyInfo? GetNavigatePro(this Type typeinfo) | 
|         { | 
|             PropertyInfo[] properties = typeinfo.GetProperties(); | 
|             foreach (PropertyInfo property in properties) | 
|             { | 
|                 Navigate? navigate = property.GetCustomAttribute<Navigate>(); | 
|                 if (navigate is not null) | 
|                 { | 
|                     return property; | 
|                 } | 
|             } | 
|             return null; | 
|         } | 
|   | 
|         public static object GetPropertyValue<T>(this Type typeinfo, T data, string propertyName) | 
|         { | 
|             if (typeinfo != typeof(T)) | 
|                 return null; | 
|   | 
|             PropertyInfo? property = typeinfo.GetProperty(propertyName); | 
|             if (property != null) | 
|             { | 
|                 return property.GetValue(data); | 
|             } | 
|             return null; | 
|         } | 
|   | 
|         public static void ValidatePageOptions<TEntity>(PageDataOptions options, ref ISugarQueryable<TEntity> sugarQueryable) | 
|         { | 
|             string where = string.Empty; | 
|             PropertyInfo[] entityProperties = typeof(TEntity).GetProperties(); | 
|             List<SearchParameters> searchParametersList = new List<SearchParameters>(); | 
|             if (options.Filter != null && options.Filter.Count > 0) | 
|             { | 
|                 searchParametersList.AddRange(options.Filter); | 
|             } | 
|             else if (!string.IsNullOrEmpty(options.Wheres)) | 
|             { | 
|                 try | 
|                 { | 
|                     searchParametersList = options.Wheres.DeserializeObject<List<SearchParameters>>(); | 
|                     options.Filter = searchParametersList; | 
|                 } | 
|                 catch { } | 
|             } | 
|             for (int i = 0; i < searchParametersList.Count; i++) | 
|             { | 
|                 if (string.IsNullOrEmpty(searchParametersList[i].Value)) | 
|                 { | 
|                     continue; | 
|                 } | 
|   | 
|                 PropertyInfo? property = entityProperties.Where(c => c.Name.ToUpper() == searchParametersList[i].Name.ToUpper()).FirstOrDefault(); | 
|   | 
|                 if (property == null) continue; | 
|   | 
|                 List<(bool, string, object)> results = property.ValidationValueForDbType(searchParametersList[i].Value.Split(',')).ToList(); | 
|                 if (results == null || results.Count() == 0) | 
|                 { | 
|                     continue; | 
|                 } | 
|                 for (int j = 0; j < results.Count(); j++) | 
|                 { | 
|                     LinqExpressionType expressionType = searchParametersList[i].DisplayType.GetLinqCondition(); | 
|                     Expression<Func<TEntity, bool>> expression = property.GetWhereExpression<TEntity>(results[j].Item3, null, expressionType); | 
|                     sugarQueryable = sugarQueryable.Where(expression); | 
|                 } | 
|             } | 
|         } | 
|     } | 
| } |