Skip to main content

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​

  1. TDatabaseMapping (or any subclass inheriting TDatabaseFactory) creates a TCatalogMetadataMIK for the master side by walking RTTI on all registered classes.
  2. It creates a second TCatalogMetadataMIK for the target by querying the live database via the dialect-specific TMetadataDBAbstract extractor.
  3. GenerateDDLCommands(master, target) produces the ordered TDDLCommand list.

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​

AttributePurpose
[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:

  1. Tables — tables present in target but not in master trigger DROP TABLE; tables in master but not in target trigger CREATE TABLE (with all columns, PK, indexes, checks).
  2. Columns — per-table, columns missing from master trigger DROP COLUMN; columns missing from target trigger ADD COLUMN; columns present in both are deep-compared on: TypeName, Size, Precision, NotNull, AutoIncrement, SortingOrder, DefaultValue, FieldType (normalized), and CharSet.
  3. Default values — compared separately: missing default triggers ALTER COLUMN default set; extra default triggers DROP DEFAULT.
  4. Column positions — only when ComparerFieldPosition = True.
  5. Primary keys — compared by name and column set; mismatches trigger DROP PK + CREATE PK.
  6. Indexes — compared by uniqueness flag and column set; drift triggers DROP INDEX + CREATE INDEX.
  7. CHECK constraints — compared per table (if the dialect supports Checks).
  8. Views — compared by script text; changes trigger DROP VIEW then CREATE VIEW.
  9. Sequences — compared by name only; missing sequences trigger CREATE SEQUENCE, extra sequences trigger DROP SEQUENCE.
  10. Foreign keys — processed last (after all structural changes): compared by referencing table, OnDelete, OnUpdate, and column sets; drift triggers DROP FK + CREATE FK.

Feature guards​

The following features are skipped automatically if the dialect does not declare them in SupportedFeatures:

  • Sequences — suppresses sequence creation/deletion
  • ForeignKeys — suppresses FK creation/deletion
  • Checks — suppresses CHECK constraint creation/deletion
  • Views — suppresses view synchronization
  • Triggers — 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.