using SqlSugar.DbConvert; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Xml.Linq; namespace SqlSugar { public class EntityMaintenance { public SqlSugarProvider Context { get; set; } public EntityInfo GetEntityInfo() { return GetEntityInfo(typeof(T)); } public EntityInfo GetEntityInfoWithAttr(Type type) { return GetEntityInfo(type); } public EntityInfo GetEntityInfo(Type type) { var attr = type?.GetCustomAttribute(); if (attr == null) { return _GetEntityInfo(type); } else if (attr.configId.ObjToString() == this.Context?.CurrentConnectionConfig?.ConfigId + "") { return _GetEntityInfo(type); } else if (this.Context.Root == null) { return _GetEntityInfo(type); } else if (!this.Context.Root.IsAnyConnection(attr.configId)) { return _GetEntityInfo(type); } else { return this.Context.Root.GetConnection(attr.configId).EntityMaintenance._GetEntityInfo(type); } } private EntityInfo _GetEntityInfo(Type type) { string cacheKey = "GetEntityInfo" + type.GetHashCode() + type.FullName + this.Context?.CurrentConnectionConfig?.ConfigId; return this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () => { return GetEntityInfoNoCache(type); }); } public EntityInfo GetEntityInfoNoCache(Type type) { EntityInfo result = new EntityInfo(); var sugarAttributeInfo = type.GetTypeInfo().GetCustomAttributes(typeof(SugarTable), false).Where(it => it is SugarTable).SingleOrDefault(); if (sugarAttributeInfo.HasValue()) { var sugarTable = (SugarTable)sugarAttributeInfo; result.DbTableName = sugarTable.TableName; result.TableDescription = sugarTable.TableDescription.ToSqlFilter(); result.IsDisabledUpdateAll = sugarTable.IsDisabledUpdateAll; result.IsDisabledDelete = sugarTable.IsDisabledDelete; result.IsCreateTableFiledSort = sugarTable.IsCreateTableFiledSort; result.Discrimator = sugarTable.Discrimator; } var indexs = type.GetCustomAttributes(typeof(SugarIndexAttribute)); if (indexs != null && indexs.Any()) { result.Indexs = indexs.Select(it => it as SugarIndexAttribute).ToList(); } if (result.TableDescription.IsNullOrEmpty()) result.TableDescription = GetTableAnnotation(type); if (this.Context.CurrentConnectionConfig.ConfigureExternalServices != null && this.Context.CurrentConnectionConfig.ConfigureExternalServices.EntityNameService != null) { if (result.DbTableName == null) { result.DbTableName = type.Name; } this.Context.CurrentConnectionConfig.ConfigureExternalServices.EntityNameService(type, result); } result.Type = type; result.EntityName = result.Type.Name; result.Columns = new List(); SetColumns(result); return result; } public string GetTableName() { return GetTableName(typeof(T)); } public string GetTableName(Type entityType) { var typeName = entityType.Name; if (this.Context.MappingTables == null || this.Context.MappingTables.Count == 0 || !this.Context.MappingTables.Any(it => it.EntityName == typeName)) { var entity = this.GetEntityInfo(entityType); if (entity.DbTableName.HasValue()) return entity.DbTableName; else return entity.EntityName; } else { var mappingInfo = this.Context.MappingTables.SingleOrDefault(it => it.EntityName == typeName); return mappingInfo == null ? typeName : mappingInfo.DbTableName; } } public string GetTableName(string entityName) { var typeName = entityName; if (this.Context.MappingTables == null || this.Context.MappingTables.Count == 0) return typeName; else { var mappingInfo = this.Context.MappingTables.SingleOrDefault(it => it.EntityName == typeName); return mappingInfo == null ? typeName : mappingInfo.DbTableName; } } public string GetEntityName(string tableName) { if (this.Context.MappingTables == null || this.Context.MappingTables.Count == 0) return tableName; else { var mappingInfo = this.Context.MappingTables.SingleOrDefault(it => it.DbTableName == tableName); return mappingInfo == null ? tableName : mappingInfo.EntityName; } } public string GetEntityName() { return this.Context.EntityMaintenance.GetEntityInfo().EntityName; } public string GetEntityName(Type type) { return this.Context.EntityMaintenance.GetEntityInfo(type).EntityName; } public string GetDbColumnName(string propertyName) { return GetDbColumnName(propertyName, typeof(T)); } public string GetDbColumnName(string propertyName, Type entityType) { var isAny = this.GetEntityInfo(entityType).Columns.Any(it => it.PropertyName.Equals(propertyName, StringComparison.CurrentCultureIgnoreCase)); Check.Exception(!isAny, "Property " + propertyName + " is Invalid"); var typeName = entityType.Name; if (this.Context.MappingColumns == null || this.Context.MappingColumns.Count == 0 || !this.Context.MappingColumns.Any(it => it.EntityName == typeName && it.PropertyName == propertyName)) { var column = this.GetEntityInfo(entityType).Columns.First(it => it.PropertyName.Equals(propertyName, StringComparison.CurrentCultureIgnoreCase)); if (column.DbColumnName.HasValue()) return column.DbColumnName; else return column.PropertyName; } else { var mappingInfo = this.Context.MappingColumns.SingleOrDefault(it => it.EntityName == typeName && it.PropertyName == propertyName); return mappingInfo == null ? propertyName : mappingInfo.DbColumnName; } } public string GetPropertyName(string dbColumnName) { var columnInfo=this.Context.EntityMaintenance.GetEntityInfo().Columns.FirstOrDefault(it=>it.DbColumnName.EqualCase(dbColumnName)); if (columnInfo != null) { return columnInfo.PropertyName; } var typeName = typeof(T).Name; if (this.Context.MappingColumns == null || this.Context.MappingColumns.Count == 0) return dbColumnName; else { var mappingInfo = this.Context.MappingColumns.SingleOrDefault(it => it.EntityName == typeName && it.DbColumnName.Equals(dbColumnName, StringComparison.CurrentCultureIgnoreCase)); return mappingInfo == null ? dbColumnName : mappingInfo.PropertyName; } } public string GetPropertyName(string dbColumnName, Type entityType) { var columnInfo = this.Context.EntityMaintenance.GetEntityInfo(entityType).Columns.FirstOrDefault(it => it.DbColumnName.EqualCase(dbColumnName)); if (columnInfo != null) { return columnInfo.PropertyName; } var typeName = entityType.Name; if (this.Context.MappingColumns == null || this.Context.MappingColumns.Count == 0) return dbColumnName; else { var mappingInfo = this.Context.MappingColumns.SingleOrDefault(it => it.EntityName == typeName && it.DbColumnName.Equals(dbColumnName, StringComparison.CurrentCultureIgnoreCase)); return mappingInfo == null ? dbColumnName : mappingInfo.PropertyName; } } public PropertyInfo GetProperty(string dbColumnName) { var propertyName = GetPropertyName(dbColumnName); return typeof(T).GetProperties().First(it => it.Name == propertyName); } /// /// Gets the text contents of this XML element node /// /// entity type /// The value of the name attribute of the XML node /// the text contents of this XML element node public string GetXElementNodeValue(Type entityType, string nodeAttributeName) { try { if (this.Context.CurrentConnectionConfig?.MoreSettings?.IsNoReadXmlDescription == true) { return ""; } if (entityType.Assembly.IsDynamic&& entityType.Assembly.FullName.StartsWith("Dynamic")) { return null; } var path = entityType.Assembly.Location; if (string.IsNullOrEmpty(path)) { return null; } FileInfo file = new FileInfo(path); string xmlPath = entityType.Assembly.Location.Replace(file.Extension, ".xml"); if (!File.Exists(xmlPath)) { return string.Empty; } XElement xe =new ReflectionInoCacheService().GetOrCreate("EntityXml_"+xmlPath,()=> XElement.Load(xmlPath)); if (xe == null) { return string.Empty; } var xeNode = xe.Element("members").Elements("member").Where(ele => ele.Attribute("name").Value == nodeAttributeName).FirstOrDefault(); if (xeNode == null) { return string.Empty; } var summary = xeNode.Element("summary"); if (summary != null) { return summary.Value.ToSqlFilter().Trim(); } else { var summaryValue = xeNode.Elements().Where(x => x.Name.ToString().EqualCase("summary")).Select(it => it.Value).FirstOrDefault(); if(summaryValue==null) return string.Empty; else return summaryValue.ToSqlFilter().Trim()??""; } } catch { Check.ExceptionEasy("ORM error reading entity class XML, check entity XML or disable reading XML: MoreSettings IsNoReadXmlDescription set to true (same place to set DbType)", "ORM读取实体类的XML出现错误,检查实体XML或者禁用读取XML: MoreSettings里面的IsNoReadXmlDescription设为true (设置DbType的同一个地方)"); throw; } } /// /// Gets the code annotation for the database table /// /// entity type /// the code annotation for the database table public string GetTableAnnotation(Type entityType) { if (entityType.IsClass() == false) { return null; } var result= GetXElementNodeValue(entityType, $"T:{entityType.FullName}"); if (string.IsNullOrEmpty(result)) { return null; } else { return result; } } /// /// Gets the code annotation for the field /// /// entity type /// column name /// the code annotation for the field public string GetPropertyAnnotation(Type entityType, string dbColumnName) { if (entityType.IsClass() == false || entityType == typeof(object)) { return null; } var result = GetXElementNodeValue(entityType, $"P:{entityType.FullName}.{dbColumnName}"); if (string.IsNullOrEmpty(result)) { return GetPropertyAnnotation(entityType.BaseType, dbColumnName); } else { return result; } } #region Primary key private void SetColumns(EntityInfo result) { foreach (var property in result.Type.GetProperties()) { EntityColumnInfo column = new EntityColumnInfo(); //var isVirtual = property.GetGetMethod().IsVirtual; //if (isVirtual) continue; var navigat=property.GetCustomAttribute(typeof(Navigate)); if (navigat != null) { column.IsIgnore = true; column.Navigat = navigat as Navigate; } var sugarColumn = property.GetCustomAttributes(typeof(SugarColumn), true) .Where(it => it is SugarColumn) .Select(it => (SugarColumn)it) .FirstOrDefault(); column.ExtendedAttribute = sugarColumn?.ExtendedAttribute; column.DbTableName = result.DbTableName; column.EntityName = result.EntityName; column.PropertyName = property.Name; column.PropertyInfo = property; column.UnderType = UtilMethods.GetUnderType(column.PropertyInfo.PropertyType); if (sugarColumn?.IsOwnsOne==true) { SetValueObjectColumns(result, property, column); } if (sugarColumn.IsNullOrEmpty()) { column.DbColumnName = property.Name; } else { if (sugarColumn.IsIgnore == false) { column.DbColumnName = sugarColumn.ColumnName.IsNullOrEmpty() ? property.Name : sugarColumn.ColumnName; column.IsPrimarykey = sugarColumn.IsPrimaryKey; column.IsIdentity = sugarColumn.IsIdentity; column.ColumnDescription = sugarColumn.ColumnDescription.ToSqlFilter(); column.IsNullable = sugarColumn.IsNullable; column.Length = sugarColumn.Length; column.OldDbColumnName = sugarColumn.OldColumnName; column.DataType = sugarColumn.ColumnDataType; column.DecimalDigits = sugarColumn.DecimalDigits; column.OracleSequenceName = sugarColumn.OracleSequenceName; column.IsOnlyIgnoreInsert = sugarColumn.IsOnlyIgnoreInsert; column.IsEnableUpdateVersionValidation = sugarColumn.IsEnableUpdateVersionValidation; column.IsTranscoding = sugarColumn.IsTranscoding; column.SerializeDateTimeFormat = sugarColumn.SerializeDateTimeFormat; column.IsJson = sugarColumn.IsJson; column.NoSerialize = sugarColumn.NoSerialize; column.DefaultValue = sugarColumn.DefaultValue; column.IndexGroupNameList = sugarColumn.IndexGroupNameList; column.UIndexGroupNameList = sugarColumn.UniqueGroupNameList; column.IsOnlyIgnoreUpdate = sugarColumn.IsOnlyIgnoreUpdate; column.IsArray = sugarColumn.IsArray; column.IsTreeKey = sugarColumn.IsTreeKey; column.SqlParameterDbType = sugarColumn.SqlParameterDbType; column.SqlParameterSize = sugarColumn.SqlParameterSize; column.CreateTableFieldSort = sugarColumn.CreateTableFieldSort; column.InsertServerTime = sugarColumn.InsertServerTime; column.InsertSql = sugarColumn.InsertSql; column.UpdateServerTime= sugarColumn.UpdateServerTime; column.UpdateSql= sugarColumn.UpdateSql; column.IsDisabledAlterColumn = sugarColumn.IsDisabledAlterColumn; column.QuerySql = sugarColumn.QuerySql; if (sugarColumn.IsJson && String.IsNullOrEmpty(sugarColumn.ColumnDataType)) { if (this.Context.CurrentConnectionConfig.DbType == DbType.PostgreSQL) { column.DataType = "json"; } else if (column.Length > 0) { column.DataType = "varchar"; } else { column.DataType = "varchar(4000)"; } } else if (typeof(Nvarchar2PropertyConvert).Equals(sugarColumn.SqlParameterDbType)&&column.DataType==null) { column.DataType = "nvarchar2"; if (column.Length == 0) { column.Length = 200; } } if (column.IsPrimarykey && column.IsOnlyIgnoreUpdate) { column.IsOnlyIgnoreUpdate = false; } } else { column.IsIgnore = true; column.NoSerialize = sugarColumn.NoSerialize; column.ColumnDescription = sugarColumn.ColumnDescription; column.IsJson = sugarColumn.IsJson; column.IsArray = sugarColumn.IsArray; } } if (column.ColumnDescription.IsNullOrEmpty()) column.ColumnDescription = GetPropertyAnnotation(result.Type, column.PropertyName); if (this.Context.MappingColumns.HasValue()) { var golbalMappingInfo = this.Context.MappingColumns.FirstOrDefault(it => it.EntityName.Equals(result.EntityName, StringComparison.CurrentCultureIgnoreCase) && it.PropertyName == column.PropertyName); if (golbalMappingInfo != null) column.DbColumnName = golbalMappingInfo.DbColumnName; } if (this.Context.IgnoreColumns.HasValue()) { var golbalMappingInfo = this.Context.IgnoreColumns.FirstOrDefault(it => it.EntityName.Equals(result.EntityName, StringComparison.CurrentCultureIgnoreCase) && it.PropertyName == column.PropertyName); if (golbalMappingInfo != null) column.IsIgnore = true; } if (this.Context.CurrentConnectionConfig.ConfigureExternalServices != null && this.Context.CurrentConnectionConfig.ConfigureExternalServices.EntityService != null) { if (!column.EntityName.ObjToString().StartsWith("<>f__AnonymousType") &&column.PropertyInfo?.ReflectedType!=typeof(DbTableInfo)) { var isOldOwnsOne = column.IsOwnsOne; this.Context.CurrentConnectionConfig.ConfigureExternalServices.EntityService(property, column); if (column.IsOwnsOne == true && isOldOwnsOne == false) { SetValueObjectColumns(result, property, column); continue; } } } if (column.PropertyInfo.DeclaringType != null && column.PropertyInfo.DeclaringType != result.Type &&result.Columns.Any(x=>x.PropertyName==column.PropertyName)) { continue; } if (column.DataType == null&& property != null&& property.PropertyType.Name.IsIn("TimeOnly")) { column.DataType = "time"; } if (column.DataType == null && property != null && property.PropertyType.Name.IsIn("DateOnly")) { column.DataType = "date"; } if (column.DataType == null&&column.UnderType == typeof(TimeSpan) ) { column.DataType = "time"; column.Length = 0; column.DecimalDigits = 0; } if (column.OracleSequenceName.HasValue() && this.Context.CurrentConnectionConfig?.MoreSettings?.EnableOracleIdentity == true) { column.OracleSequenceName = null; } result.Columns.Add(column); } } private void SetValueObjectColumns(EntityInfo result, PropertyInfo property, EntityColumnInfo column) { column.IsIgnore = true; column.IsOwnsOne = true; Check.ExceptionEasy(property.PropertyType.IsClass() == false, column.PropertyName + " IsOwnsOne必须用在类上面", column.PropertyName + "IsOwnsOne must be used on the class"); Check.ExceptionEasy(property.PropertyType.FullName.IsCollectionsList() == true, column.PropertyName + " IsOwnsOne必须用在类上面", column.PropertyName + "IsOwnsOne must be used on the class"); var ownsOne = this.GetEntityInfoNoCache(property.PropertyType); foreach (var item in ownsOne.Columns) { if (result.Columns.Any(it => it.PropertyName.EqualCase(item.PropertyName) || it.DbColumnName.EqualCase(item.DbColumnName))) { Check.ExceptionEasy($" {result.EntityName} "+ item.PropertyName+ " 存在重复定义 (IsOwnsOne) ", $" {result.EntityName} " + item.PropertyName + " Duplicate definition exists (IsOwnsOne)"); } item.ForOwnsOnePropertyInfo = column.PropertyInfo; result.Columns.Add(item); } } #endregion } }