public EFEntityDescription() { Type entityType = typeof(TEntity); // Словарь: имя сущности - SQL идентификатор сущности извлеченные из контекста приложения. Dictionary <string, string> entitiesIds = typeof(ApplicationDbContext).GetProperties().Where(p => { return(p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet <>)); }).ToDictionary(p => p.PropertyType.GenericTypeArguments.First().Name, p => GetEntityId(p.Name)); // Получаем идентификатор SQL указанной сущности из словаря tableNames или атрибута Table. TableAttribute tableAttribute = entityType.GetCustomAttribute <TableAttribute>(); EntityId = tableAttribute == null || string.IsNullOrWhiteSpace(tableAttribute.Name) ? entitiesIds[entityType.Name] : GetEntityId(tableAttribute.Name); // Массив вложенных и невложенных свойств текущей сущности. PropertyInfo[] allowedProperties = entityType.GetProperties().Where(p => { return(!Attribute.IsDefined(p, typeof(NotMappedAttribute)) && p.GetMethod.IsPublic && !p.GetMethod.IsAbstract && !p.GetMethod.IsStatic); }).ToArray(); // Список ключей: невложенное свойство - SQL идентификатор свойства текущей сущности. EntityProperties = allowedProperties.Where(p => { return((p.PropertyType == typeof(string) || p.PropertyType.IsValueType) && !p.GetMethod.IsVirtual); }) .ToDictionary(p => p, p => { var columnAttribute = p.GetCustomAttribute <ColumnAttribute>(); string propertyName = columnAttribute == null || string.IsNullOrWhiteSpace(columnAttribute.Name) ? p.Name : columnAttribute.Name; return(GetPropertyId(EntityId, propertyName)); }); // Подключаемые сущности. Type[] joinedEntities = allowedProperties.Where(p => { return(p.GetMethod.IsVirtual && entitiesIds.ContainsKey(p.PropertyType.Name) && p.PropertyType.IsClass && !typeof(IEnumerable).IsAssignableFrom(p.PropertyType) && p.PropertyType.GetProperties().Any(np => { return !Attribute.IsDefined(np, typeof(NotMappedAttribute)) && (np.PropertyType.IsValueType || np.PropertyType == typeof(string)) && np.GetMethod.IsPublic && !np.GetMethod.IsAbstract && !np.GetMethod.IsStatic; })); }) .Select(p => p.PropertyType).ToArray(); // Список ключей: вложенное свойство - SQL идентификатор свойства текущей сущности. var joinedEntitiesProperties = new List <KeyValuePair <PropertyInfo, string> >(); foreach (Type joinedEntity in joinedEntities) { // Получаем идентификатор SQL подключаемой сущности из словаря tableNames или атрибута Table. TableAttribute joinedTableAttribute = joinedEntity.GetCustomAttribute <TableAttribute>(); string joinedEntityId = joinedTableAttribute == null || string.IsNullOrWhiteSpace(joinedTableAttribute.Name) ? entitiesIds[joinedEntity.Name] : GetEntityId(joinedTableAttribute.Name); // Список ключей: невложенное свойство - идентификатор SQL свойства подключаемой сущности. IEnumerable <KeyValuePair <PropertyInfo, string> > joinedEntityProperties = joinedEntity.GetProperties() .Where(p => { return(!Attribute.IsDefined(p, typeof(NotMappedAttribute)) && p.GetMethod.IsPublic && (p.PropertyType == typeof(string) || p.PropertyType.IsValueType) && !p.GetMethod.IsAbstract && !p.GetMethod.IsStatic && !p.GetMethod.IsVirtual); }) .Select(p => { var columnAttribute = p.GetCustomAttribute <ColumnAttribute>(); var propertyName = columnAttribute == null || string.IsNullOrWhiteSpace(columnAttribute.Name) ? p.Name : columnAttribute.Name; propertyName = GetPropertyId(joinedEntityId, propertyName); return(new KeyValuePair <PropertyInfo, string>(p, propertyName)); }); // Добавляем пары ключ - значение невложенных свойств подключаемой сущности // к вложенным свойствам указанной в параметре типе сущности. joinedEntitiesProperties.AddRange(joinedEntityProperties); } JoinedEntitiesProperties = joinedEntitiesProperties.ToDictionary(p => p.Key, p => p.Value); // Список кортежей описания подключаемой SQL сущности. JoinedEntitiesInfo = joinedEntities.Select(e => { string PKey = JoinedEntitiesProperties[e.GetProperties().Single(p => { return(Attribute.IsDefined(p, typeof(KeyAttribute)) || p.Name.Contains($"{e.Name}id", StringComparison.OrdinalIgnoreCase)); })]; string FKey = EntityProperties.Single(p => p.Key.Name.Contains($"{e.Name}Id", StringComparison.OrdinalIgnoreCase) ).Value; return(entitiesIds[e.Name], PKey, FKey); }).ToList(); }