using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Data; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using VOL.Core.Configuration; using VOL.Core.Const; using VOL.Core.Utilities; using VOL.Entity; using VOL.Entity.DomainModels; /* * jxx 2017-08-09 * 通用实体属操作 */ namespace VOL.Core.Extensions { public static class EntityProperties { public static string GetExpressionPropertyFirst(this Expression> properties) { string[] arr = properties.GetExpressionProperty(); if (arr.Length > 0) return arr[0]; return ""; } /// /// 获取对象里指定成员名称 /// /// /// 格式 Expression> exp = x => new { x.字段1, x.字段2 };或x=>x.Name /// public static string[] GetExpressionProperty(this Expression> properties) { if (properties == null) return new string[] { }; if (properties.Body is NewExpression) return ((NewExpression)properties.Body).Members.Select(x => x.Name).ToArray(); if (properties.Body is MemberExpression) return new string[] { ((MemberExpression)properties.Body).Member.Name }; if (properties.Body is UnaryExpression) return new string[] { ((properties.Body as UnaryExpression).Operand as MemberExpression).Member.Name }; throw new Exception("未实现的表达式"); } public static string ValidateHashInEntity(this Type typeinfo, Dictionary dic) { return typeinfo.ValidateDicInEntity(dic, false); } public static void RemoveNotExistColumns(this Type typeinfo, List cols) { } /// /// 获取所有字段的名称 /// /// /// public static List GetAtrrNames(this Type typeinfo) { return typeinfo.GetProperties().Select(c => c.Name).ToList(); } public static void IsExistColumns(this Type typeinfo) { } public static Dictionary GetColumType(this PropertyInfo[] properties) { return properties.GetColumType(false); } public static Dictionary GetColumType(this PropertyInfo[] properties, bool containsKey) { Dictionary dictionary = new Dictionary(); foreach (PropertyInfo property in properties) { if (!containsKey && property.IsKey()) { continue; } var keyVal = GetColumnType(property, true); dictionary.Add(keyVal.Key, keyVal.Value); } return dictionary; } private static readonly Dictionary entityMapDbColumnType = new Dictionary() { {typeof(int),SqlDbTypeName.Int }, {typeof(int?),SqlDbTypeName.Int }, {typeof(long),SqlDbTypeName.BigInt }, {typeof(long?),SqlDbTypeName.BigInt }, {typeof(decimal),"decimal(18, 5)" }, {typeof(decimal?),"decimal(18, 5)" }, {typeof(double),"decimal(18, 5)" }, {typeof(double?),"decimal(18, 5)" }, {typeof(float),"decimal(18, 5)" }, {typeof(float?),"decimal(18, 5)" }, {typeof(Guid),"UniqueIdentifier" }, {typeof(Guid?),"UniqueIdentifier" }, {typeof(byte),"tinyint" }, {typeof(byte?),"tinyint" }, {typeof(string),"nvarchar" } }; /// /// 返回属性的字段及数据库类型 /// /// /// 是否包括后字段具体长度:nvarchar(100) /// public static KeyValuePair GetColumnType(this PropertyInfo property, bool lenght = false) { string colType = ""; object objAtrr = property.GetTypeCustomAttributes(typeof(ColumnAttribute), out bool asType); if (asType) { colType = ((ColumnAttribute)objAtrr).TypeName.ToLower(); if (!string.IsNullOrEmpty(colType)) { //不需要具体长度直接返回 if (!lenght) { return new KeyValuePair(property.Name, colType); } if (colType == "decimal" || colType == "double" || colType == "float") { objAtrr = property.GetTypeCustomAttributes(typeof(DisplayFormatAttribute), out asType); colType += "(" + (asType ? ((DisplayFormatAttribute)objAtrr).DataFormatString : "18,5") + ")"; } ///如果是string,根据 varchar或nvarchar判断最大长度 if (property.PropertyType.ToString() == "System.String") { colType = colType.Split("(")[0]; objAtrr = property.GetTypeCustomAttributes(typeof(MaxLengthAttribute), out asType); if (asType) { int length = ((MaxLengthAttribute)objAtrr).Length; colType += "(" + (length < 1 || length > (colType.StartsWith("n") ? 8000 : 4000) ? "max" : length.ToString()) + ")"; } else { colType += "(max)"; } } return new KeyValuePair(property.Name, colType); } } if (entityMapDbColumnType.TryGetValue(property.PropertyType, out string value)) { colType = value; } else { colType = SqlDbTypeName.NVarChar; } if (lenght && colType == SqlDbTypeName.NVarChar) { colType = "nvarchar(max)"; } return new KeyValuePair(property.Name, colType); } /// /// /// /// 将数组转换成sql语句 /// 指定FieldType数据库字段类型 /// /// public static string GetArraySql(this object[] array, FieldType fieldType) { if (array == null || array.Count() == 0) { return string.Empty; } string columnType = string.Empty; List arrrayEntityList = array.Select(x => new ArrayEntity { column1 = x.ToString() }).ToList(); return arrrayEntityList.GetEntitySql(false, null, null, null, fieldType); } /// ///要执行的sql语句如:通过EntityToSqlTempName.Temp_Insert0.ToString()字符串占位,生成的的sql语句会把EntityToSqlTempName.Temp_Insert0.ToString()替换成生成的sql临时表数据 /// string sql = " ;DELETE FROM " + typeEntity.Name + " where " + typeEntity.GetKeyName() + /// " in (select * from " + EntityToSqlTempName.Temp_Insert0.ToString() + ")"; /// /// /// /// 指定生成的数组值的类型 /// /// public static string GetArraySql(this object[] array, FieldType fieldType, string sql) { if (array == null || array.Count() == 0) { return string.Empty; } string columnType = string.Empty; List arrrayEntityList = array.Select(x => new ArrayEntity { column1 = x.ToString() }).ToList(); return arrrayEntityList.GetEntitySql(false, sql, null, null, fieldType); } public static string GetArraySql(this object[] array, string sql) { return array.GetArraySql(typeof(T).GetFieldType(), sql); } /// /// 根据实体获取key的类型,用于update或del操作 /// /// /// public static FieldType GetFieldType(this Type typeEntity) { FieldType fieldType; string columnType = typeEntity.GetProperties().Where(x => x.Name == typeEntity.GetKeyName()).ToList()[0].GetColumnType(false).Value; switch (columnType) { case SqlDbTypeName.Int: fieldType = FieldType.Int; break; case SqlDbTypeName.BigInt: fieldType = FieldType.BigInt; break; case SqlDbTypeName.VarChar: fieldType = FieldType.VarChar; break; case SqlDbTypeName.UniqueIdentifier: fieldType = FieldType.UniqueIdentifier; break; default: fieldType = FieldType.NvarChar; break; } return fieldType; } public static string GetEntitySql(this IEnumerable entityList, bool containsKey = false, string sql = null, Expression> ignoreFields = null, Expression> fixedColumns = null, FieldType? fieldType = null ) { if (entityList == null || entityList.Count() == 0) return ""; PropertyInfo[] propertyInfo = typeof(T).GetProperties().ToArray(); if (propertyInfo.Count() == 0) { propertyInfo = entityList.ToArray()[0].GetType().GetGenericProperties().ToArray(); } propertyInfo = propertyInfo.GetGenericProperties().ToArray(); string[] arr = null; if (fixedColumns != null) { arr = fixedColumns.GetExpressionToArray(); PropertyInfo keyProperty = typeof(T).GetKeyProperty(); propertyInfo = propertyInfo.Where(x => (containsKey && x.Name == keyProperty.Name) || arr.Contains(x.Name)).ToArray(); } if (ignoreFields != null) { arr = ignoreFields.GetExpressionToArray(); propertyInfo = propertyInfo.Where(x => !arr.Contains(x.Name)).ToArray(); } Dictionary dictProperties = propertyInfo.GetColumType(containsKey); if (fieldType != null) { string realType = fieldType.ToString(); if ((int)fieldType == 0 || (int)fieldType == 1) { realType += "(max)"; } dictProperties = new Dictionary { { dictProperties.Select(x => x.Key).ToList()[0], realType } }; } if (dictProperties.Keys.Count * entityList.Count() > 50 * 3000) { throw new Exception("写入数据太多,请分开写入。"); } string cols = string.Join(",", dictProperties.Select(c => "[" + c.Key + "]" + " " + c.Value)); StringBuilder declareTable = new StringBuilder(); string tempTablbe = "#" + EntityToSqlTempName.TempInsert.ToString(); declareTable.Append("CREATE TABLE " + tempTablbe + " (" + cols + ")"); declareTable.Append("\r\n"); //参数总数量 int parCount = (dictProperties.Count) * (entityList.Count()); int takeCount = 0; int maxParsCount = 2050; if (parCount > maxParsCount) { //如果参数总数量超过2100,设置每次分批循环写入表的大小 takeCount = maxParsCount / dictProperties.Count; } int count = 0; StringBuilder stringLeft = new StringBuilder(); StringBuilder stringCenter = new StringBuilder(); StringBuilder stringRight = new StringBuilder(); int index = 0; foreach (T entity in entityList) { //每1000行需要分批写入(数据库限制每批至多写入1000行数据) if (index == 0 || index >= 1000 || takeCount - index == 0) { if (stringLeft.Length > 0) { declareTable.AppendLine( stringLeft.Remove(stringLeft.Length - 2, 2).Append("',").ToString() + stringCenter.Remove(stringCenter.Length - 1, 1).Append("',").ToString() + stringRight.Remove(stringRight.Length - 1, 1).ToString()); stringLeft.Clear(); stringCenter.Clear(); stringRight.Clear(); } stringLeft.AppendLine("exec sp_executesql N'SET NOCOUNT ON;"); stringCenter.Append("N'"); index = 0; count = 0; } stringLeft.Append(index == 0 ? "; INSERT INTO " + tempTablbe + " values (" : " "); index++; foreach (PropertyInfo property in propertyInfo) { if (!containsKey && property.IsKey()) { continue; } string par = "@v" + count; stringLeft.Append(par + ","); stringCenter.Append(par + " " + dictProperties[property.Name] + ","); object val = property.GetValue(entity); if (val == null) { stringRight.Append(par + "=NUll,"); } else { stringRight.Append(par + "='" + val.ToString().Replace("'", "''''") + "',"); } count++; } stringLeft.Remove(stringLeft.Length - 1, 1); stringLeft.Append("),("); } if (stringLeft.Length > 0) { declareTable.AppendLine( stringLeft.Remove(stringLeft.Length - 2, 2).Append("',").ToString() + stringCenter.Remove(stringCenter.Length - 1, 1).Append("',").ToString() + stringRight.Remove(stringRight.Length - 1, 1).ToString()); stringLeft.Clear(); stringCenter.Clear(); stringRight.Clear(); } if (!string.IsNullOrEmpty(sql)) { sql = sql.Replace(EntityToSqlTempName.TempInsert.ToString(), tempTablbe); declareTable.AppendLine(sql); } else { declareTable.AppendLine(" SELECT " + (string.Join(",", fixedColumns?.GetExpressionToArray() ?? new string[] { "*" })) + " FROM " + tempTablbe); } if (tempTablbe.Substring(0, 1) == "#") { declareTable.AppendLine("; drop table " + tempTablbe); } return declareTable.ToString(); } /// ///此方法适用于数据量少,只有几列数据,不超过1W行,或几十列数据不超过1000行的情况下使用 /// 大批量的数据考虑其他方式 /// 將datatable生成sql語句,替換datatable作為參數傳入存儲過程 /// /// /// public static string GetDataTableSql(this DataTable table) { Dictionary dictCloumn = new Dictionary(); for (int i = 0; i < table.Columns.Count; i++) { dictCloumn.Add(table.Columns[i].ColumnName, " nvarchar(max)"); } //参数总数量 int parCount = (dictCloumn.Count) * (table.Rows.Count); int takeCount = 0; int maxParsCount = 2050; if (parCount > maxParsCount) { //如果参数总数量超过2100,设置每次分批循环写入表的大小 takeCount = maxParsCount / dictCloumn.Count; } if (dictCloumn.Keys.Count * table.Rows.Count > 50 * 3000) { throw new Exception("写入数据太多,请分开写入。"); } string cols = string.Join(",", dictCloumn.Select(c => "[" + c.Key + "]" + " " + c.Value)); StringBuilder declareTable = new StringBuilder(); string tempTablbe = "#Temp_Insert0"; declareTable.Append("CREATE TABLE " + tempTablbe + " (" + cols + ")"); declareTable.Append("\r\n"); int count = 0; StringBuilder stringLeft = new StringBuilder(); StringBuilder stringCenter = new StringBuilder(); StringBuilder stringRight = new StringBuilder(); int index = 0; foreach (DataRow row in table.Rows) { //每1000行需要分批写入(数据库限制每批至多写入1000行数据) if (index == 0 || index >= 1000 || takeCount - index == 0) { if (stringLeft.Length > 0) { declareTable.AppendLine( stringLeft.Remove(stringLeft.Length - 2, 2).Append("',").ToString() + stringCenter.Remove(stringCenter.Length - 1, 1).Append("',").ToString() + stringRight.Remove(stringRight.Length - 1, 1).ToString()); stringLeft.Clear(); stringCenter.Clear(); stringRight.Clear(); } // sbLeft.AppendLine(" INSERT INTO @toInsert0"); stringLeft.AppendLine("exec sp_executesql N'SET NOCOUNT ON;"); stringCenter.Append("N'"); index = 0; count = 0; } stringLeft.Append(index == 0 ? "; INSERT INTO " + tempTablbe + " values (" : " "); index++; foreach (KeyValuePair keyValue in dictCloumn) { string par = "@v" + count; stringLeft.Append(par + ","); stringCenter.Append(par + " " + keyValue.Value + ","); object val = row[keyValue.Key]; if (val == null) { stringRight.Append(par + "=NUll,"); } else { stringRight.Append(par + "='" + val.ToString().Replace("'", "''''") + "',"); } count++; } stringLeft.Remove(stringLeft.Length - 1, 1); stringLeft.Append("),("); } if (stringLeft.Length > 0) { declareTable.AppendLine( stringLeft.Remove(stringLeft.Length - 2, 2).Append("',").ToString() + stringCenter.Remove(stringCenter.Length - 1, 1).Append("',").ToString() + stringRight.Remove(stringRight.Length - 1, 1).ToString()); stringLeft.Clear(); stringCenter.Clear(); stringRight.Clear(); } declareTable.AppendLine(" SELECT * FROM " + tempTablbe); if (tempTablbe.Substring(0, 1) == "#") { declareTable.AppendLine("; drop table " + tempTablbe); } return declareTable.ToString(); } public static string GetKeyName(this Type typeinfo) { return typeinfo.GetProperties().GetKeyName(); } public static string GetKeyType(this Type typeinfo) { string keyType = typeinfo.GetProperties().GetKeyName(true); if (keyType == "varchar") { return "varchar(max)"; } else if (keyType != "nvarchar") { return keyType; } else { return "nvarchar(max)"; } } public static string GetKeyName(this PropertyInfo[] properties) { return properties.GetKeyName(false); } /// /// 获取key列名 /// /// /// true获取key对应类型,false返回对象Key的名称 /// public static string GetKeyName(this PropertyInfo[] properties, bool keyType) { string keyName = string.Empty; foreach (PropertyInfo propertyInfo in properties) { if (!propertyInfo.IsKey()) continue; if (!keyType) return propertyInfo.Name; var attributes = propertyInfo.GetCustomAttributes(typeof(ColumnAttribute), false); //如果没有ColumnAttribute的需要单独再验证,下面只验证有属性的 if (attributes.Length > 0) return ((ColumnAttribute)attributes[0]).TypeName.ToLower(); else return GetColumType(new PropertyInfo[] { propertyInfo }, true)[propertyInfo.Name]; } return keyName; } /// /// 获取主键字段 /// /// /// public static PropertyInfo GetKeyProperty(this Type entity) { return entity.GetProperties().GetKeyProperty(); } public static PropertyInfo GetKeyProperty(this PropertyInfo[] properties) { return properties.Where(c => c.IsKey()).FirstOrDefault(); } public static bool IsKey(this PropertyInfo propertyInfo) { object[] keyAttributes = propertyInfo.GetCustomAttributes(typeof(KeyAttribute), false); if (keyAttributes.Length > 0) return true; return false; } /// /// 获取 公司代码 字段 /// /// /// public static PropertyInfo GetCompanyProperty(this PropertyInfo[] properties) { return properties.Where(c => c.IsCompany()).FirstOrDefault(); } public static bool IsCompany(this PropertyInfo propertyInfo) { object[] keyAttributes = propertyInfo.GetCustomAttributes(typeof(AuthRange), false); foreach (Object attributes in keyAttributes) { AuthRange dbi = (AuthRange)attributes; if (null != dbi) { if (dbi.Name == "COMPANY") return true; } } return false; } /// /// 获取部门代码 字段 /// /// /// public static PropertyInfo GetDeptProperty(this PropertyInfo[] properties) { return properties.Where(c => c.IsDept()).FirstOrDefault(); } public static bool IsDept(this PropertyInfo propertyInfo) { object[] keyAttributes = propertyInfo.GetCustomAttributes(typeof(AuthRange), false); foreach (Object attributes in keyAttributes) { AuthRange dbi = (AuthRange)attributes; if (null != dbi) { if (dbi.Name == "DEPT") return true; } } return false; } /// /// 获取 父节点ID 字段 /// 默认为空。如一个表管理多个父表,定义时需分别写明父表名称 /// 子表数据实体当中,当中与父表连接的字段需增加 【ParentId属性】 , /// 如一个子表关联多个子表,需要在属性中添加父表名字;如只关联一个父表,可以传空字符串进去 /// 在调用时,如不传表名,将会取得子表中第一个包含【ParentId属性】的字段 /// /// /// /// public static PropertyInfo GetParentIdProperty(this Type enentity ,string ParentIdName = "") { return enentity.GetProperties().GetParentIdProperty(ParentIdName); } public static PropertyInfo GetParentIdProperty(this PropertyInfo[] properties,string ParentIdName="") { var parentidarray = properties.Where(c => c.IsParentId(ParentIdName)).ToArray(); if (parentidarray.Length > 0) { return parentidarray[0]; } else { parentidarray = properties.Where(c => c.IsParentId("")).ToArray(); if (parentidarray.Length > 0) { return parentidarray[0]; } else { parentidarray = properties.Where(c => c.HaveParentId()).ToArray(); return parentidarray[0]; } } return null; } public static bool IsParentId(this PropertyInfo propertyInfo,string ParentIdName) { object[] keyAttributes = propertyInfo.GetCustomAttributes(typeof(ParentId), false); foreach (Object attributes in keyAttributes) { ParentId dbi = (ParentId)attributes; if (null != dbi) { if (dbi.Name == ParentIdName) return true; } } return false; } public static bool HaveParentId(this PropertyInfo propertyInfo) { object[] keyAttributes = propertyInfo.GetCustomAttributes(typeof(ParentId), false); foreach (Object attributes in keyAttributes) { ParentId dbi = (ParentId)attributes; if (null != dbi) { return true; } } return false; } public static PropertyInfo[] GetEditableFalse(this Type enentity) { return enentity.GetProperties().GetEditableFalse(); } public static PropertyInfo[] GetEditableFalse(this PropertyInfo[] properties) { var parentidarray = properties.Where(c => c.IsEditableFalse()).ToArray(); return parentidarray; } public static bool IsEditableFalse(this PropertyInfo propertyInfo) { object[] keyAttributes = propertyInfo.GetCustomAttributes(typeof(EditableAttribute), false); foreach (Object attributes in keyAttributes) { EditableAttribute dbi = (EditableAttribute)attributes; if (null != dbi) { if (dbi.AllowEdit==false) return true; } } return false; } private static string[] _userEditFields { get; set; } private static string[] UserEditFields { get { if (_userEditFields != null) return _userEditFields; _userEditFields = AppSetting.CreateMember.GetType().GetProperties() .Select(x => x.GetValue(AppSetting.ModifyMember)?.ToString()?.ToLower()) .Where(w => !string.IsNullOrEmpty(w)).ToArray(); return _userEditFields; } } /// /// 获取实体所有可以编辑的列 /// /// /// public static string[] GetEditField(this Type type) { Type editType = typeof(EditableAttribute); PropertyInfo[] propertyInfo = type.GetProperties(); string keyName = propertyInfo.GetKeyName(); return propertyInfo.Where(x => x.Name != keyName && (UserEditFields.Contains(x.Name.ToLower()) || x.ContainsCustomAttributes(editType))).Select(s => s.Name).ToArray(); } /// /// 获取新建时所能插入的数据。 /// 即包括主键和editable=true的 /// /// /// public static string[] GetInsertField(this Type type) { Type editType = typeof(EditableAttribute); PropertyInfo[] propertyInfo = type.GetProperties(); string keyName = propertyInfo.GetKeyName(); return propertyInfo.Where(x => !x.IsEditableFalse()).Select(s => s.Name).ToArray(); } /// /// 判断是否包含某个属性: /// 如 [Editable(true)] // public string MO { get; set; }包含Editable /// /// /// /// public static bool ContainsCustomAttributes(this PropertyInfo propertyInfo, Type type) { propertyInfo.GetTypeCustomAttributes(type, out bool contains); return contains; } public static List ContainsCustomAttributes(this Type obj, Type containType) { List proList = new List(); foreach (PropertyInfo pro in obj.GetProperties()) { if (pro.GetTypeCustomAttributes(containType) != null) { proList.Add(pro); } } return proList; } /// /// 获取PropertyInfo指定属性 /// /// /// /// public static object GetTypeCustomAttributes(this PropertyInfo propertyInfo, Type type, out bool asType) { object[] attributes = propertyInfo.GetCustomAttributes(type, false); if (attributes.Length == 0) { asType = false; return new string[0]; } asType = true; return attributes[0]; } /// /// 验证集合的属性 /// /// /// /// /// public static WebResponseContent ValidationEntityList(this List entityList, Expression> expression = null) { WebResponseContent responseData = new WebResponseContent(); foreach (T entity in entityList) { responseData = entity.ValidationEntity(expression); if (!responseData.Status) { return responseData; } } responseData.Status = true; return responseData; } /// /// 指定需要验证的字段 /// /// /// /// 对指定属性进行验证x=>{x.Name,x.Size} /// public static WebResponseContent ValidationEntity(this T entity, Expression> expression = null, Expression> validateProperties = null) { return ValidationEntity(entity, expression?.GetExpressionProperty(), validateProperties?.GetExpressionProperty()); } /// /// specificProperties=null并且validateProperties=null,对所有属性验证,只验证其是否合法,不验证是否为空(除属性标识指定了不能为空外) /// specificProperties!=null,对指定属性校验,并且都必须有值 /// null并且validateProperties!=null,对指定属性校验,不判断是否有值 /// /// /// /// 验证指定的属性,并且非空判断 /// 验证指定属性,只对字段合法性判断,不验证是否为空 /// public static WebResponseContent ValidationEntity(this T entity, string[] specificProperties, string[] validateProperties = null) { WebResponseContent responseData = new WebResponseContent(); if (entity == null) return responseData.Error("对象不能为null"); PropertyInfo[] propertyArray = typeof(T).GetProperties(); //若T为object取不到属性 if (propertyArray.Length == 0) { propertyArray = entity.GetType().GetProperties(); } List compareProper = new List(); //只验证数据合法性,验证非空 if (specificProperties != null && specificProperties.Length > 0) { compareProper.AddRange(propertyArray.Where(x => specificProperties.Contains(x.Name))); } //只验证数据合法性,不验证非空 if (validateProperties != null && validateProperties.Length > 0) { compareProper.AddRange(propertyArray.Where(x => validateProperties.Contains(x.Name))); } if (compareProper.Count() > 0) { propertyArray = compareProper.ToArray(); } foreach (PropertyInfo propertyInfo in propertyArray) { object value = propertyInfo.GetValue(entity); //设置默认状态的值 if (propertyInfo.Name == "Enable" || propertyInfo.Name == "AuditStatus") { if (value == null) { propertyInfo.SetValue(entity, 0); continue; } } //若存在specificProperties并且属性为数组specificProperties中的值,校验时就需要判断是否为空 var reslut = propertyInfo.ValidationProperty(value, specificProperties != null && specificProperties.Contains(propertyInfo.Name) ? true : false ); if (!reslut.Item1) return responseData.Error(reslut.Item2); } return responseData.OK(); } /// /// 获取数据库类型,不带长度,如varchar(100),只返回的varchar /// /// /// public static string GetSqlDbType(this PropertyInfo propertyInfo) { string dbType = propertyInfo.GetTypeCustomValue(x => new { x.TypeName }); if (string.IsNullOrEmpty(dbType)) { return dbType; } dbType = dbType.ToLower(); if (dbType.Contains(SqlDbTypeName.NVarChar)) { dbType = SqlDbTypeName.NVarChar; } else if (dbType.Contains(SqlDbTypeName.VarChar)) { dbType = SqlDbTypeName.VarChar; } else if (dbType.Contains(SqlDbTypeName.NChar)) { dbType = SqlDbTypeName.NChar; } else if (dbType.Contains(SqlDbTypeName.Char)) { dbType = SqlDbTypeName.Char; } return dbType; } /// /// 验证数据库字段类型与值是否正确, /// /// propertyInfo为当字段,当前字段必须有ColumnAttribute属性, /// 如字段:标识为数据库int类型[Column(TypeName="int")] public int Id { get; set; } /// 如果是小数float或Decimal必须对propertyInfo字段加DisplayFormatAttribute属性 /// /// /// IEnumerable<(bool, string, object)> bool成否校验成功,string校验失败信息,object,当前校验的值 public static IEnumerable<(bool, string, object)> ValidationValueForDbType(this PropertyInfo propertyInfo, params object[] values) { string dbTypeName = propertyInfo.GetTypeCustomValue(c => c.TypeName); foreach (object value in values) { yield return dbTypeName.ValidationVal(value, propertyInfo); } } public static bool ValidationRquiredValueForDbType(this PropertyInfo propertyInfo, object value, out string message) { if (value == null || value?.ToString()?.Trim() == "") { message = $"{propertyInfo.GetDisplayName()}不能为空"; return false; } var result = propertyInfo.GetProperWithDbType().ValidationVal(value, propertyInfo); message = result.Item2; return result.Item1; } 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; } /// /// 验证数据库字段类型与值是否正确, /// /// 数据库字段类型(如varchar,nvarchar,decimal,不要带后面长度如:varchar(50)) /// 值 /// 要验证的类的属性,若不为null,则会判断字符串的长度是否正确 /// (bool, string, object)bool成否校验成功,string校验失败信息,object,当前校验的值 public static (bool, string, object) ValidationVal(this string dbType, object value, PropertyInfo propertyInfo = null) { if (string.IsNullOrEmpty(dbType)) { dbType = propertyInfo != null ? propertyInfo.GetProperWithDbType() : SqlDbTypeName.NVarChar; } dbType = dbType.ToLower(); string val = value?.ToString(); //验证长度 string reslutMsg = string.Empty; if (dbType == SqlDbTypeName.Int || dbType == SqlDbTypeName.BigInt) { if (!value.IsInt()) reslutMsg = "只能为有效整数"; } else if (dbType == SqlDbTypeName.DateTime || dbType == SqlDbTypeName.Date || dbType == SqlDbTypeName.SmallDateTime || dbType == SqlDbTypeName.SmallDate ) { if (!value.IsDate()) { try { string strDate = DateTime.FromOADate(Convert.ToInt32(value)).ToString("d"); value = DateTime.Parse(strDate).ToString("yyyy-MM-dd"); } catch (Exception e) { reslutMsg = "必须为日期格式"; } } } else if (dbType == SqlDbTypeName.Float || dbType == SqlDbTypeName.Decimal || dbType == SqlDbTypeName.Double) { //string formatString = string.Empty; //if (propertyInfo != null) // formatString = propertyInfo.GetTypeCustomValue(x => x.DataFormatString); //if (string.IsNullOrEmpty(formatString)) // throw new Exception("请对字段" + propertyInfo?.Name + "添加DisplayFormat属性标识"); if (!val.IsNumber(null)) { // string[] arr = (formatString ?? "10,0").Split(','); // reslutMsg = $"整数{arr[0]}最多位,小数最多{arr[1]}位"; 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 > 20000) { reslutMsg = $"字符长度最多【20000】"; } else { int length = propertyInfo.GetTypeCustomValue(x => new { x.Length }).GetInt(); 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}】个字符。"; //} else if (length < 8000 && val.Length > length) { reslutMsg = $"最多只能【{length}】个字符。"; } } } if (!string.IsNullOrEmpty(reslutMsg) && propertyInfo != null) { reslutMsg = propertyInfo.GetDisplayName() + reslutMsg; } return (reslutMsg == "" ? true : false, reslutMsg, value); } public static string GetDisplayName(this PropertyInfo property) { string displayName = property.GetTypeCustomValue(x => new { x.Name }); if (string.IsNullOrEmpty(displayName)) { return property.Name; } return displayName; } /// /// 验证每个属性的值是否正确 /// /// /// 属性的值 /// 是否指定当前属性必须有值 /// public static (bool, string, object) ValidationProperty(this PropertyInfo propertyInfo, object objectVal, bool required) { if (propertyInfo.IsKey()) { return (true, null, objectVal); } string val = objectVal == null ? "" : objectVal.ToString().Trim(); string requiredMsg = string.Empty; if (!required) { var reuireVal = propertyInfo.GetTypeCustomValues(x => new { x.AllowEmptyStrings, x.ErrorMessage }); if (reuireVal != null && !Convert.ToBoolean(reuireVal["AllowEmptyStrings"])) { required = true; requiredMsg = reuireVal["ErrorMessage"]; } } //如果不要求为必填项并且值为空,直接返回 if (!required && string.IsNullOrEmpty(val)) return (true, null, objectVal); if ((required && val == string.Empty)) { if (requiredMsg != "") return (false, requiredMsg, objectVal); string propertyName = propertyInfo.GetTypeCustomValue(x => new { x.Name }); return (false, requiredMsg + (string.IsNullOrEmpty(propertyName) ? propertyInfo.Name : propertyName) + "不能为空", objectVal); } //列名 string typeName = propertyInfo.GetSqlDbType(); //如果没有ColumnAttribute的需要单独再验证,下面只验证有属性的 if (typeName == null) { return (true, null, objectVal); } //验证长度 return typeName.ValidationVal(val, propertyInfo); } /// /// 获取属性的指定属性 /// /// /// /// public static object GetTypeCustomAttributes(this MemberInfo member, Type type) { object[] obj = member.GetCustomAttributes(type, false); if (obj.Length == 0) return null; return obj[0]; } /// /// 获取类的指定属性 /// /// /// /// public static object GetTypeCustomAttributes(this Type entity, Type type) { object[] obj = entity.GetCustomAttributes(type, false); if (obj.Length == 0) return null; return obj[0]; } /// /// 获取类的多个指定属性的值 /// /// 当前类 /// 指定的类 /// 指定属性的值 格式 Expression> exp = x => new { x.字段1, x.字段2 }; /// 返回的是字段+value public static Dictionary GetTypeCustomValues(this MemberInfo member, Expression> expression) { var attr = member.GetTypeCustomAttributes(typeof(TEntity)); if (attr == null) { return null; } string[] propertyName = expression.GetExpressionProperty(); Dictionary propertyKeyValues = new Dictionary(); foreach (PropertyInfo property in attr.GetType().GetProperties()) { if (propertyName.Contains(property.Name)) { propertyKeyValues[property.Name] = (property.GetValue(attr) ?? string.Empty).ToString(); } } return propertyKeyValues; } /// /// 获取类的单个指定属性的值(只会返回第一个属性的值) /// /// 当前类 /// 指定的类 /// 指定属性的值 格式 Expression> exp = x => new { x.字段1, x.字段2 }; /// public static string GetTypeCustomValue(this MemberInfo member, Expression> expression) { var propertyKeyValues = member.GetTypeCustomValues(expression); if (propertyKeyValues == null || propertyKeyValues.Count == 0) { return null; } return propertyKeyValues.First().Value ?? ""; } /// /// 判断hash的列是否为对应的实体,并且值是否有效 /// /// /// /// 移除不存在字段 /// public static string ValidateDicInEntity(this Type typeinfo, Dictionary dic, bool removeNotContains, string[] ignoreFields = null) { return typeinfo.ValidateDicInEntity(dic, removeNotContains, true, ignoreFields); } public static string ValidateDicInEntity(this Type type, List> dicList, bool removeNotContains, bool removerKey, string[] ignoreFields = null) { PropertyInfo[] propertyInfo = type.GetProperties(); string reslutMsg = string.Empty; foreach (Dictionary dic in dicList) { reslutMsg = type.ValidateDicInEntity(dic, propertyInfo, removeNotContains, removerKey, ignoreFields); if (!string.IsNullOrEmpty(reslutMsg)) return reslutMsg; } return reslutMsg; } public static string ValidateDicInEntity(this Type type, Dictionary dic, bool removeNotContains, bool removerKey, string[] ignoreFields = null) { return type.ValidateDicInEntity(dic, null, removeNotContains, removerKey, ignoreFields); } /// /// 判断hash的列是否为对应的实体,并且值是否有效 /// /// /// /// 移除不存在字段 /// 移除主键 /// private static string ValidateDicInEntity(this Type typeinfo, Dictionary dic, PropertyInfo[] propertyInfo, bool removeNotContains, bool removerKey, string[] ignoreFields = null) { if (dic == null || dic.Count == 0) { return "参数无效"; } if (propertyInfo == null) propertyInfo = typeinfo.GetProperties().Where(x => x.PropertyType.Name != "List`1").ToArray(); // 不存在的字段直接移除 dic.Where(x => !propertyInfo.Any(p => p.Name == x.Key)).Select(s => s.Key).ToList().ForEach(f => { dic.Remove(f); }); string keyName = typeinfo.GetKeyName(); //移除主键 if (removerKey) { dic.Remove(keyName); } foreach (PropertyInfo property in propertyInfo) { //忽略与主键的字段不做验证 if (property.Name == keyName || (ignoreFields != null && ignoreFields.Contains(property.Name))) continue; //不在编辑中的列,是否也要必填 if (!dic.ContainsKey(property.Name)) { //移除主键默认为新增数据,将不在编辑列中的有默认值的数据设置为默认值 //如果为true默认为添加功能,添加操作所有不能为空的列也必须要提交 if (property.GetCustomAttributes(typeof(RequiredAttribute)).Count() > 0 && property.PropertyType != typeof(int) && property.PropertyType != typeof(long) && property.PropertyType != typeof(byte) && property.PropertyType != typeof(decimal) ) { return property.GetTypeCustomValue(x => x.Name) + "为必须提交项"; } continue; } bool isEdit = property.ContainsCustomAttributes(typeof(EditableAttribute)); //不是编辑列的直接移除,并且不是主键 //removerKey=true,不保留主键,直接移除 //removerKey=false,保留主键,属性与主键不同的直接移除 // if (!isEdit && (removerKey || (!removerKey && property.Name != keyName))) if (!isEdit) { if (property.GetCustomAttributes(typeof(RequiredAttribute)).Count() > 0) { return property.GetTypeCustomValue(x => x.Name) + "没有配置好Model为编辑列"; } dic.Remove(property.Name); continue; } ////移除忽略的不保存的数据 //if (property.ContainsCustomAttributes(typeof(JsonIgnoreAttribute))) //{ // hash.Remove(property.Name); // continue; //} //验证数据类型,不验证是否为空 var result = property.ValidationProperty(dic[property.Name], false); if (!result.Item1) return result.Item2; //将所有空值设置为null if (dic[property.Name] != null && dic[property.Name].ToString() == string.Empty) dic[property.Name] = null; } return string.Empty; } /// /// 获取表带有EntityAttribute属性的真实表名 /// /// /// public static string GetEntityTableName(this Type type) { Attribute attribute = type.GetCustomAttribute(typeof(EntityAttribute)); if (attribute != null && attribute is EntityAttribute) { return (attribute as EntityAttribute).TableName ?? type.Name; } return type.Name; } /// /// 获取表带有EntityAttribute属性的表中文名 /// /// /// public static string GetEntityTableCnName(this Type type) { Attribute attribute = type.GetCustomAttribute(typeof(EntityAttribute)); if (attribute != null && attribute is EntityAttribute) { return (attribute as EntityAttribute).TableCnName; } return string.Empty; } /// /// 将实体映射到输出到ApiOutput实体上,如果没有输入实体,则返回null /// /// /// //public static object MapToOutput( this T entity, Type type = null) //{ // Type sourceType = typeof(T); // //list转换 // if (sourceType is System.Collections.IList) // { // System.Collections.IList list = entity as System.Collections.IList; // sourceType = list[0].GetType(); // } // if (type == null) // { // EntityAttribute attribute = sourceType.GetCustomAttribute(); // if (attribute == null || attribute.ApiOutput == null) // return null; // type = attribute.ApiOutput; // } // object outPutObject = Activator.CreateInstance(type); // PropertyInfo[] outPutPropertyInfo = type.GetProperties(); // PropertyInfo[] propertyInfo = sourceType.GetProperties(); // foreach (var property in outPutPropertyInfo) // { // PropertyInfo info= propertyInfo.Where(x => x.Name == property.Name).FirstOrDefault(); // if (info!=null) // { // property.SetValue(outPutObject, info.GetValue(entity)); // } // } // return outPutObject; //} private static object MapToInstance(this Type reslutType, object sourceEntity, PropertyInfo[] sourcePro, PropertyInfo[] reslutPro, string[] sourceFilterField, string[] reslutFilterField, string mapType = null) { mapType = mapType ?? GetMapType(reslutType); if (sourcePro == null) { sourcePro = sourceEntity.GetType().GetProperties(); } if (reslutPro == null) { reslutPro = reslutType.GetProperties(); ; } object newObj = Activator.CreateInstance(reslutType); if (mapType == "Dictionary") { if (sourceFilterField != null && sourceFilterField.Length > 0) { sourcePro = sourcePro.Where(x => sourceFilterField.Contains(x.Name)).ToArray(); } foreach (var property in sourcePro) { (newObj as System.Collections.IDictionary).Add(property.Name, property.GetValue(sourceEntity)); } return newObj; } if (reslutFilterField != null && reslutFilterField.Count() > 0) { reslutPro.Where(x => reslutFilterField.Contains(x.Name)); } foreach (var property in reslutPro) { PropertyInfo info = sourcePro.Where(x => x.Name == property.Name).FirstOrDefault(); if (!(info != null && info.PropertyType == property.PropertyType)) continue; property.SetValue(newObj, info.GetValue(sourceEntity)); } return newObj; } private static string GetMapType(Type type) { return typeof(Dictionary<,>) == type ? "Dictionary" : "entity"; } /// /// 将数据源映射到新的数据中,目前只支持List映射到List或TSource映射到TResult /// 目前只支持Dictionary或实体类型 /// /// /// /// /// 只映射返回对象的指定字段,若为null则默认为全部字段 /// 只映射数据源对象的指定字段,若为null则默认为全部字段 /// public static TResult MapToObject(this TSource source, Expression> resultExpression, Expression> sourceExpression = null ) where TResult : class { if (source == null) return null; string[] sourceFilterField = sourceExpression == null ? typeof(TSource).GetProperties().Select(x => x.Name).ToArray() : sourceExpression.GetExpressionProperty(); string[] reslutFilterField = resultExpression?.GetExpressionProperty(); if (!(source is System.Collections.IList)) return MapToInstance(typeof(TResult), source, null, null, sourceFilterField, reslutFilterField) as TResult; Type sourceType = null; Type resultType = null; System.Collections.IList sourceList = source as System.Collections.IList; sourceType = sourceList[0].GetType(); resultType = (typeof(TResult)).GenericTypeArguments[0]; System.Collections.IList reslutList = Activator.CreateInstance(typeof(TResult)) as System.Collections.IList; PropertyInfo[] sourcePro = sourceType.GetProperties(); PropertyInfo[] resultPro = resultType.GetProperties(); string mapType = GetMapType(resultType); for (int i = 0; i < sourceList.Count; i++) { var reslutobj = MapToInstance(resultType, sourceList[i], sourcePro, resultPro, sourceFilterField, reslutFilterField, mapType); reslutList.Add(reslutobj); } return reslutList as TResult; } /// /// 将一个实体的赋到另一个实体上,应用场景: /// 两个实体,a a1= new a();b b1= new b(); a1.P=b1.P; a1.Name=b1.Name; /// /// /// /// /// /// 指定对需要的字段赋值,格式x=>new {x.Name,x.P},返回的结果只会对Name与P赋值 public static void MapValueToEntity(this TSource source, TResult result, Expression> expression = null) where TResult : class { if (source == null) return; string[] fields = expression?.GetExpressionToArray(); PropertyInfo[] reslutPro = fields == null ? result.GetType().GetProperties() : result.GetType().GetProperties().Where(x => fields.Contains(x.Name)).ToArray(); PropertyInfo[] sourcePro = source.GetType().GetProperties(); foreach (var property in reslutPro) { PropertyInfo info = sourcePro.Where(x => x.Name == property.Name).FirstOrDefault(); if (info != null && info.PropertyType == property.PropertyType) { property.SetValue(result, info.GetValue(source)); } } } /// /// 设置默认字段的值"CreateID", "Creator", "CreateDate","ModifyID", "Modifier", "ModifyDate" /// /// /// true=新增设置"CreateID", "Creator", "CreateDate"值 /// false=编辑设置"ModifyID", "Modifier", "ModifyDate"值 /// public static SaveModel SetDefaultVal(this SaveModel saveDataModel, TableDefaultColumns defaultColumns, UserInfo userInfo = null) { SetDefaultVal(saveDataModel.MainData, defaultColumns, userInfo); if (saveDataModel.DetailData != null && saveDataModel.DetailData.Count > 0) { foreach (var item in saveDataModel.DetailData) { if (item.Count == 0) continue; SetDefaultVal(item, defaultColumns, userInfo); } } return saveDataModel; } /// /// 设定 建立人/建立人id/建立时间 三字段 /// /// /// /// /// public static TSource SetCreateDefaultVal(this TSource source, UserInfo userInfo = null) { return SetDefaultVal(source, AppSetting.CreateMember, userInfo); } public static TSource SetModifyDefaultVal(this TSource source, UserInfo userInfo = null) { return SetDefaultVal(source, AppSetting.ModifyMember, userInfo); } public static TSource SetDept(this TSource source, UserInfo userInfo = null) { userInfo = userInfo ?? ManageUser.UserContext.Current.UserInfo; foreach (PropertyInfo property in typeof(TSource).GetProperties()) { string field = property.Name.ToLower(); if (field == "DEPTGID") property.SetValue(source, userInfo.Dept_Id); } return source; } /// /// /// 设置默认字段的值如:"CreateID", "Creator", "CreateDate","ModifyID", "Modifier", "ModifyDate" /// /// /// true=新增设置"CreateID", "Creator", "CreateDate"值 /// false=编辑设置"ModifyID", "Modifier", "ModifyDate"值 /// private static TSource SetDefaultVal(this TSource source, TableDefaultColumns defaultColumns, UserInfo userInfo = null) { userInfo = userInfo ?? ManageUser.UserContext.Current.UserInfo; foreach (PropertyInfo property in typeof(TSource).GetProperties()) { string field = property.Name.ToLower(); if (field == defaultColumns.UserIdField?.ToLower()) property.SetValue(source, userInfo.User_Id); if (field == defaultColumns.UserNameField?.ToLower()) property.SetValue(source, userInfo.UserTrueName); if (field == defaultColumns.DateField?.ToLower()) property.SetValue(source, DateTime.Now); } return source; } private static Dictionary SetDefaultVal(this Dictionary dic, TableDefaultColumns defaultColumns, UserInfo userInfo = null) { userInfo = userInfo ?? ManageUser.UserContext.Current.UserInfo; KeyValuePair valuePair = dic.Where(x => x.Key.ToLower() == defaultColumns.UserIdField?.ToLower()).FirstOrDefault(); if (valuePair.Key != null || defaultColumns.UserIdField != null) { dic[valuePair.Key ?? defaultColumns.UserIdField] = userInfo.User_Id; } valuePair = dic.Where(x => x.Key.ToLower() == defaultColumns.UserNameField?.ToLower()).FirstOrDefault(); if (valuePair.Key != null || defaultColumns.UserNameField != null) { dic[valuePair.Key ?? defaultColumns.UserNameField] = userInfo.UserTrueName; } valuePair = dic.Where(x => x.Key.ToLower() == defaultColumns.DateField?.ToLower()).FirstOrDefault(); if (valuePair.Key != null || defaultColumns.DateField != null) { dic[valuePair.Key ?? defaultColumns.DateField] = DateTime.Now; } return dic; } public static Dictionary SetCreateDefaultVal(this Dictionary dic) { return SetDefaultVal(dic, AppSetting.CreateMember); } public static Dictionary SetModifyDefaultVal(this Dictionary dic) { return SetDefaultVal(dic, AppSetting.ModifyMember); } } public class ArrayEntity { public string column1 { get; set; } } public enum FieldType { VarChar = 0, NvarChar, Int, BigInt, UniqueIdentifier } public enum EntityToSqlTempName { TempInsert = 0 } }