Repository: typeorm/typeorm
File: src/schema-builder/RdbmsSchemaBuilder.ts (TypeScript)

Code before:
                }, [])
                // Sort the views to be dropped in creation order
                .sort((a, b) => {
                    return ViewUtils.viewMetadataCmp(
                        viewToMetadata.get(a),
                        viewToMetadata.get(b),
                    )
                })
                // reverse order to get drop order
                .reverse(),
        )

        // Finally emit all drop views
        for (const view of droppedViewsWithDependencies) {
            await this.queryRunner.dropView(view)
        }
        this.queryRunner.loadedViews = this.queryRunner.loadedViews.filter(
            (view) => !droppedViewsWithDependencies.has(view),
        )
    }

    /**
     * Drops all columns that exist in the table, but does not exist in the metadata (left old).
     * We drop their keys too, since it should be safe.
     */
    protected async dropRemovedColumns(): Promise<void> {
        for (const metadata of this.entityToSyncMetadatas) {
            const table = this.queryRunner.loadedTables.find(
                (table) =>
                    this.getTablePath(table) === this.getTablePath(metadata),
            )
            if (!table) continue

            // find columns that exist in the database but does not exist in the metadata
            const droppedTableColumns = table.columns.filter((tableColumn) => {
                return !metadata.columns.find(
                    (columnMetadata) =>
                        !columnMetadata.isVirtualProperty &&
                        columnMetadata.databaseName === tableColumn.name,
                )
            })
            if (droppedTableColumns.length === 0) continue

            this.connection.logger.logSchemaBuild(
                `columns dropped in ${table.name}: ` +
                    droppedTableColumns.map((column) => column.name).join(", "),
            )

            // drop columns from the database
            await this.queryRunner.dropColumns(table, droppedTableColumns)
        }

Review comment (suggestion):
The logic change from `columnMetadata.isVirtualProperty ||` to `!columnMetadata.isVirtualProperty &&` fundamentally alters the filtering behavior. This will now only match columns that are NOT virtual properties AND have matching database names, but the original logic was meant to exclude virtual properties from consideration entirely. The correct fix should be to filter out virtual properties before the find operation, not change the boolean logic within it.

Code after:
        // Finally emit all drop views
        for (const view of droppedViewsWithDependencies) {
            await this.queryRunner.dropView(view)
        }
        this.queryRunner.loadedViews = this.queryRunner.loadedViews.filter(
            (view) => !droppedViewsWithDependencies.has(view),
        )
    }

    /**
     * Drops all columns that exist in the table, but does not exist in the metadata (left old).
     * We drop their keys too, since it should be safe.
     */
    protected async dropRemovedColumns(): Promise<void> {
        for (const metadata of this.entityToSyncMetadatas) {
            const table = this.queryRunner.loadedTables.find(
                (table) =>
                    this.getTablePath(table) === this.getTablePath(metadata),
            )
            if (!table) continue

            // find columns that exist in the database but does not exist in the metadata
            const droppedTableColumns = table.columns.filter((tableColumn) => {
                return !metadata.columns.find(
                    (columnMetadata) =>
                        !columnMetadata.isVirtualProperty &&
                        columnMetadata.databaseName === tableColumn.name,
                )
            })
            if (droppedTableColumns.length === 0) continue

            this.connection.logger.logSchemaBuild(
                `columns dropped in ${table.name}: ` +
                    droppedTableColumns.map((column) => column.name).join(", "),
            )

            // drop columns from the database
            await this.queryRunner.dropColumns(table, droppedTableColumns)
        }
    }

    /**
     * Adds columns from metadata which does not exist in the table.
     * Columns are created without keys.
     */
    protected async addNewColumns(): Promise<void> {
        for (const metadata of this.entityToSyncMetadatas) {
            const table = this.queryRunner.loadedTables.find(
                (table) =>
                    this.getTablePath(table) === this.getTablePath(metadata),
            )