dengjunjie
2025-07-09 7ca9651f81d7b84f054194d3d46fdbd1d9c8b922
ÏîÄ¿´úÂë/WMS/WIDESEA_WMSServer/WIDESEA_Core/Utilities/EntityProperties.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,367 @@
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, 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);
        }
        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()) /*&& !dic.ContainsKey(property.Name.FirstLetterToUpper())*/)
                {
                    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);
                }
            }
        }
    }
}