using SqlSugar; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using WIDESEA_Core.Const; using WIDESEA_Core.DB.Models; using WIDESEA_Core.Helper; namespace WIDESEA_Core.Utilities { public static class EntityProperties { /// /// 验证数据库字段类型与值是否正确, /// /// 数据库字段类型(如varchar,nvarchar,decimal,不要带后面长度如:varchar(50)) /// 值 /// 要验证的类的属性,若不为null,则会判断字符串的长度是否正确 /// (bool, string, object)bool成否校验成功,string校验失败信息,object,当前校验的值 public static (bool, string, object) ValidationVal(this PropertyInfo propertyInfo, object value) { string dbType = ""; SugarColumn sugarColumn = null; if (propertyInfo != null) { sugarColumn = propertyInfo.GetCustomAttribute(); dbType = propertyInfo != 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, null); } //判断双字节与单字段 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); } private static readonly Dictionary ProperWithDbType = new Dictionary() { { 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; } public static string ValidateDicInEntity(this Type typeinfo, List> dicList, bool removerKey, string[] ignoreFields = null) { PropertyInfo[] propertyInfo = typeinfo.GetProperties(); string reslutMsg = string.Empty; foreach (Dictionary dic in dicList) { reslutMsg = typeinfo.ValidateDicInEntity(dic, removerKey, propertyInfo, ignoreFields); if (!string.IsNullOrEmpty(reslutMsg)) return reslutMsg; } return reslutMsg; } /// /// 判断hash的列是否为对应的实体,并且值是否有效 /// /// /// /// 移除不存在字段 /// 移除主键 /// public static string ValidateDicInEntity(this Type typeinfo, Dictionary 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(); if (sugarColumn == null) 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; } string str = dic.GetValueOrDefault(property.Name.FirstLetterToLower(), "").ToString(); //将所有空值设置为null if (dic[property.Name.FirstLetterToLower()] != null && str == string.Empty) dic[property.Name.FirstLetterToLower()] = null; } return string.Empty; } /// /// 安全获取字典值,如果键不存在或值为null则返回默认值 /// /// 字典键的类型 /// 字典值的类型 /// 字典实例 /// 键 /// 默认值 /// 字典值或默认值 public static TValue GetValueOrDefault(this IDictionary dictionary, TKey key, TValue defaultValue = default) { if (dictionary == null) throw new ArgumentNullException(nameof(dictionary)); return dictionary.TryGetValue(key, out TValue value) && value != null ? value : defaultValue; } 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(); 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(); 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(); 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(); if (navigate is not null) { return navigate.GetName(); } } return null; } public static void SetDetailId(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(); if (navigate is not null) { return property; } } return null; } public static object GetPropertyValue(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; } } }