Guide: Compare Schemas
MetaDbDiff supports two comparison modes. Both produce an ordered list of TDDLCommand objects through the same internal pipeline.
Mode 1: Model-to-Database
The master schema is extracted from registered Delphi entity classes via RTTI. The target schema is extracted from the live database.
How it works
TDatabaseMapping(or any subclass inheritingTDatabaseFactory) creates aTCatalogMetadataMIKfor the master side by walking RTTI on all registered classes.- It creates a second
TCatalogMetadataMIKfor the target by querying the live database via the dialect-specificTMetadataDBAbstractextractor. GenerateDDLCommands(master, target)produces the orderedTDDLCommandlist.
Entity registration
Register classes in one of two ways:
Explicit — call TRegisterClass.RegisterEntity (from MetaDbDiff.Mapping.Register) before BuildDatabase. There is no automatic implicit registration triggered by a uses clause; classes must be registered manually.
uses MetaDbDiff.Mapping.Register;
TRegisterClass.RegisterEntity(TCustomer);
TRegisterClass.RegisterEntity(TOrder);
TRegisterClass.RegisterEntity(TOrderItem);
Supported ORM attributes
| Attribute | Purpose |
|---|---|
[Table('TABLE_NAME')] | Maps the class to a physical table |
[Column('COL', ftString, 100)] | Maps a property to a column with type and size |
[PrimaryKey('COL', TAutoIncType.AutoInc)] | Declares the primary key |
[ForeignKey('FK_NAME', 'FROM_COL', 'REF_TABLE', 'TO_COL')] | Declares a foreign key |
[Indexe('IDX_NAME', 'COL1,COL2')] | Declares an index |
[Sequence('GEN_NAME', 0, 1)] | Declares a sequence/generator |
[Check('CHK_NAME', 'CONDITION')] | Declares a CHECK constraint |
[NotNullConstraint] | Marks the column as NOT NULL |
Mode 2: Database-to-Database
Both schemas are extracted from live databases.
uses
MetaDbDiff.Database.Compare,
DataEngine.Factory.FireDAC;
var
LCompare: TDatabaseCompare;
begin
// Master = source of truth; Target = database to evolve
LCompare := TDatabaseCompare.Create(LSourceConn, LTargetConn);
try
LCompare.BuildDatabase;
finally
LCompare.Free;
end;
end;
TDatabaseCompare connects both databases, extracts both catalogs, then delegates to TDatabaseFactory.GenerateDDLCommands.
What the comparison engine checks
The engine (TDatabaseFactory) performs the following checks in order:
- Tables — tables present in target but not in master trigger
DROP TABLE; tables in master but not in target triggerCREATE TABLE(with all columns, PK, indexes, checks). - Columns — per-table, columns missing from master trigger
DROP COLUMN; columns missing from target triggerADD COLUMN; columns present in both are deep-compared on:TypeName,Size,Precision,NotNull,AutoIncrement,SortingOrder,DefaultValue,FieldType(normalized), andCharSet. - Default values — compared separately: missing default triggers
ALTER COLUMNdefault set; extra default triggersDROP DEFAULT. - Column positions — only when
ComparerFieldPosition = True. - Primary keys — compared by name and column set; mismatches trigger
DROP PK+CREATE PK. - Indexes — compared by uniqueness flag and column set; drift triggers
DROP INDEX+CREATE INDEX. - CHECK constraints — compared per table (if the dialect supports
Checks). - Views — compared by script text; changes trigger
DROP VIEWthenCREATE VIEW. - Sequences — compared by name only; missing sequences trigger
CREATE SEQUENCE, extra sequences triggerDROP SEQUENCE. - Foreign keys — processed last (after all structural changes): compared by referencing table,
OnDelete,OnUpdate, and column sets; drift triggersDROP FK+CREATE FK.
Feature guards
The following features are skipped automatically if the dialect does not declare them in SupportedFeatures:
Sequences— suppresses sequence creation/deletionForeignKeys— suppresses FK creation/deletionChecks— suppresses CHECK constraint creation/deletionViews— suppresses view synchronizationTriggers— suppresses trigger synchronization
Controlling foreign-key and trigger state during migration
The engine automatically wraps the DDL batch with:
-- disable all FKs
-- disable all triggers
-- ... structural DDL commands ...
-- enable all FKs
-- enable all triggers
These envelope commands are generated by GenerateEnableForeignKeys(False) / GenerateEnableForeignKeys(True) and their trigger equivalents on the dialect generator.