private async Task AddDbObjectNodes(TreeNode parentNode, string database, DatabaseObjectType databaseObjectType = DatabaseObjectType.None, bool createFolderNode = true)
        {
            DbInterpreter dbInterpreter = this.GetDbInterpreter(database);

            SchemaInfo schemaInfo = databaseObjectType == DatabaseObjectType.None ? new SchemaInfo() :
                                    await dbInterpreter.GetSchemaInfoAsync(new SchemaInfoFilter()
            {
                DatabaseObjectType = databaseObjectType
            });

            this.ClearNodes(parentNode);

            this.AddTreeNodes(parentNode, databaseObjectType, DatabaseObjectType.Table, schemaInfo.Tables, createFolderNode, true);
            this.AddTreeNodes(parentNode, databaseObjectType, DatabaseObjectType.View, schemaInfo.Views, createFolderNode);
            this.AddTreeNodes(parentNode, databaseObjectType, DatabaseObjectType.Function, schemaInfo.Functions, createFolderNode);
            this.AddTreeNodes(parentNode, databaseObjectType, DatabaseObjectType.Procedure, schemaInfo.Procedures, createFolderNode);

            foreach (UserDefinedType userDefinedType in schemaInfo.UserDefinedTypes)
            {
                string text = $"{userDefinedType.Name}({userDefinedType.Type})";

                string imageKeyName = nameof(userDefinedType);

                TreeNode node = DbObjectsTreeHelper.CreateTreeNode(userDefinedType.Name, text, imageKeyName);
                node.Tag = userDefinedType;

                parentNode.Nodes.Add(node);
            }
        }
        private void ShowLoading(TreeNode node)
        {
            string loadingImageKey = "Loading.gif";
            string loadingText     = "loading...";

            if (this.IsOnlyHasFakeChild(node))
            {
                node.Nodes[0].ImageKey = loadingImageKey;
                node.Nodes[0].Text     = loadingText;
            }
            else
            {
                node.Nodes.Add(DbObjectsTreeHelper.CreateTreeNode("Loading", loadingText, loadingImageKey));
            }
        }
        public async Task LoadTree(DatabaseType dbType, ConnectionInfo connectionInfo)
        {
            this.databaseType   = dbType;
            this.connectionInfo = connectionInfo;

            this.tvDbObjects.Nodes.Clear();

            DbInterpreter dbInterpreter = DbInterpreterHelper.GetDbInterpreter(dbType, connectionInfo, simpleInterpreterOption);

            List <Database> databases = await dbInterpreter.GetDatabasesAsync();

            foreach (Database database in databases)
            {
                TreeNode node = DbObjectsTreeHelper.CreateTreeNode(database, true);

                this.tvDbObjects.Nodes.Add(node);
            }

            if (this.tvDbObjects.Nodes.Count == 1)
            {
                this.tvDbObjects.SelectedNode = this.tvDbObjects.Nodes[0];
                this.tvDbObjects.Nodes[0].Expand();
            }
        }
        private async Task AddTableObjectNodes(TreeNode treeNode, Table table, DatabaseObjectType databaseObjectType)
        {
            string        nodeName      = treeNode.Name;
            string        database      = this.GetDatabaseNode(treeNode).Name;
            DbInterpreter dbInterpreter = this.GetDbInterpreter(database, false);

            dbInterpreter.Subscribe(this);

            SchemaInfo schemaInfo = await dbInterpreter.GetSchemaInfoAsync(new SchemaInfoFilter()
            {
                Strict = true, DatabaseObjectType = databaseObjectType, TableNames = new string[] { table.Name }
            });

            this.ClearNodes(treeNode);

            #region Columns
            if (nodeName == nameof(DbObjectTreeFolderType.Columns))
            {
                foreach (TableColumn column in schemaInfo.TableColumns)
                {
                    string text         = this.GetColumnText(dbInterpreter, table, column);
                    bool   isPrimaryKey = schemaInfo.TablePrimaryKeys.Any(item => item.Columns.Any(t => t.ColumnName == column.Name));
                    bool   isForeignKey = schemaInfo.TableForeignKeys.Any(item => item.Columns.Any(t => t.ColumnName == column.Name));
                    string imageKeyName = isPrimaryKey ? nameof(TablePrimaryKey) : (isForeignKey ? nameof(TableForeignKey) : nameof(TableColumn));

                    TreeNode node = DbObjectsTreeHelper.CreateTreeNode(column.Name, text, imageKeyName);
                    node.Tag = column;

                    treeNode.Nodes.Add(node);
                }
            }
            #endregion

            if (nodeName == nameof(DbObjectTreeFolderType.Triggers))
            {
                treeNode.AddDbObjectNodes(schemaInfo.TableTriggers);
            }

            #region Indexes
            if (nodeName == nameof(DbObjectTreeFolderType.Indexes) && schemaInfo.TableIndexes.Any())
            {
                foreach (TableIndex index in schemaInfo.TableIndexes)
                {
                    bool   isUnique   = index.IsUnique;
                    string strColumns = string.Join(",", index.Columns.OrderBy(item => item.Order).Select(item => item.ColumnName));
                    string content    = isUnique ? $"(Unique, {strColumns})" : $"({strColumns})";

                    string text         = $"{index.Name}{content}";
                    string imageKeyName = nameof(TableIndex);

                    TreeNode node = DbObjectsTreeHelper.CreateTreeNode(index.Name, text, imageKeyName);
                    node.Tag = index;

                    treeNode.Nodes.Add(node);
                }
            }
            #endregion
            if (nodeName == nameof(DbObjectTreeFolderType.Keys))
            {
                foreach (TablePrimaryKey key in schemaInfo.TablePrimaryKeys)
                {
                    TreeNode node = DbObjectsTreeHelper.CreateTreeNode(key);
                    treeNode.Nodes.Add(node);
                }

                foreach (TableForeignKey key in schemaInfo.TableForeignKeys)
                {
                    TreeNode node = DbObjectsTreeHelper.CreateTreeNode(key);
                    treeNode.Nodes.Add(node);
                }
            }

            #region Constraints
            if (nodeName == nameof(DbObjectTreeFolderType.Constraints) && schemaInfo.TableConstraints.Any())
            {
                foreach (TableConstraint constraint in schemaInfo.TableConstraints)
                {
                    TreeNode node = DbObjectsTreeHelper.CreateTreeNode(constraint);
                    treeNode.Nodes.Add(node);
                }
            }
            #endregion

            this.Feedback("");
        }