/// <summary>
        /// Populates the catalogs in the server object from an IDataReader. This method is used by
        /// GetXXX() and BuildXXX() methods. They are marked public, in case they are needed for custom work.
        /// Use the GetXXX() and BuildXXX() methods for default metadata access.
        /// </summary>
        /// <param name="server">The server to fill catalogs only.</param>
        /// <param name="reader">The DbDataReader to read in metadata.</param>
        public static void Read(
            Server server,
            IDataReader reader)
        {
            var factory = new CatalogFactory(reader);

            while (reader.Read())
            {
                factory.CreateCatalog(server, reader);
            }
        }
        /// <summary>
        /// Populates the catalogs in the server object from a DBDataReader. This method is used by
        /// GetXXX() and BuildXXX() methods. They are marked public, in case they are needed for custom work.
        /// Use the GetXXX() and BuildXXX() methods for default metadata access. Note that IDataReader did
        /// not expose the ReadAsync method.
        /// </summary>
        /// <param name="server">The server to fill catalogs only.</param>
        /// <param name="reader">The DbDataReader to read in metadata.</param>
        /// <param name="cancellationToken">The optional cancellation token.</param>
        public static async Task ReadAsync(
            Server server,
            DbDataReader reader,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            var factory = new CatalogFactory(reader);

            while (await reader.ReadAsync(cancellationToken))
            {
                cancellationToken.ThrowIfCancellationRequested();
                factory.CreateCatalog(server, reader);
            }
        }