//Метод получения первичной информации о связях таблиц из БД
        private bool GetDBTablesRelations(RelationMatrix relationMatrix)
        {
            ;
            using (var sConn = new NpgsqlConnection(sConnStr)) {
                //Проверка подключения
                try {
                    sConn.Open();
                }
                catch {
                    return(false);
                }
                //Формируем команду
                var sCommand = new NpgsqlCommand {
                    Connection  = sConn,
                    CommandText = @"
SELECT t1.table_name AS base_table,
       t1.column_name AS base_column,
       t2.table_name AS aim_table,
       t2.column_name AS aim_column
FROM information_schema.key_column_usage AS t1
         JOIN
     information_schema.constraint_column_usage AS t2
     ON t1.constraint_schema = t2.constraint_schema AND t1.constraint_name = t2.constraint_name
         JOIN
     information_schema.table_constraints AS t3
     ON t2.constraint_schema = t3.constraint_schema AND t2.constraint_name = t3.constraint_name
WHERE t3.constraint_type = 'FOREIGN KEY' AND t1.constraint_schema = 'public'
"
                };
                //Запрос и заполнение списка
                using (var reader = sCommand.ExecuteReader()) {
                    while (reader.Read())
                    {
                        var    baseTableName       = (string)reader["base_table"];
                        var    baseColumnName      = (string)reader["base_column"];
                        var    aimTableName        = (string)reader["aim_table"];
                        var    aimColumnName       = (string)reader["aim_column"];
                        string connectionCondition = $"\"{baseTableName}\".\"{baseColumnName}\" = \"{aimTableName}\".\"{aimColumnName}\"";

                        //Создаём двухстороннюю связь
                        relationMatrix[baseTableName][aimTableName] =
                            new RelationMatixElem {
                            ViaTable            = aimTableName,
                            ConnectionCondition = connectionCondition
                        };
                        relationMatrix[aimTableName][baseTableName] =
                            new RelationMatixElem {
                            ViaTable            = baseTableName,
                            ConnectionCondition = connectionCondition
                        };
                    }
                }
            }
            return(true);
        }
        //Метод формирования матрицы связей таблиц БД. (параметр)(матрица достижимости)
        public RelationMatrix GetRelationMatrix(List <TableInfo> tables)
        {
            RelationMatrix relationMatrix = new RelationMatrix(tables);

            //Заполним матрицу первоначальными данными. Не смогли - ошибка
            if (!GetDBTablesRelations(relationMatrix))
            {
                return(null);
            }
            //Составляем список имён всех таблиц
            var allTableNames = new List <string>();

            foreach (var table in tables)
            {
                allTableNames.Add(table.TableName);
            }
            //Заполняем матрицу
            foreach (var baseTableName in allTableNames)
            {
                //Получаем список соседей этой таблицы
                var neighborTableNames = relationMatrix.GetNeighborTablesNames(baseTableName);
                //Для каждого соседа ищем достижимые вершины
                foreach (var neighborTableName in neighborTableNames)
                {
                    var reachebleTables = new HashSet <string>(); //множество достижимых из соседней таблицы таблиц
                    reachebleTables.Add(baseTableName);           //базовая таблица достижима - в неё идти не надо
                    relationMatrix.GetConnectedTablesNames(reachebleTables, neighborTableName);
                    reachebleTables.Remove(baseTableName);        //убираем базовую таблицу из множества достижимых - здесь она нам не нужна
                    //Помечаем достижимые из соседа вершины как достижимые из базовой таблицы, делаем в матрице соотв. запись
                    foreach (var reachebleTableName in reachebleTables)
                    {
                        relationMatrix[baseTableName][reachebleTableName] = new RelationMatixElem {
                            ViaTable            = neighborTableName,
                            ConnectionCondition = relationMatrix[baseTableName][neighborTableName].ConnectionCondition
                        }
                    }
                    ;
                }
            }
            return(relationMatrix);
        }