ERD Enterprise Features
DDL round-trips, schema comparison and migration scripts on top of the ERD family
Beyond drawing entities and relationships, the ERD family can move schemas in and out of databases: export entities to DDL, parse existing DDL back into entities, compare two schemas and generate forward or rollback migration scripts. This is the ERD family page's companion for schema work.
Table of Contents
Entity Columns, Indexes and Keys
ERDEntity keeps the table definition in text form, so the canvas and the schema tools share one source of truth:
| Member | Type | Description |
|---|---|---|
EntityName | string | Table name. |
Columns | string | Column definitions, one per line. |
Indexes | string | Index definitions (including unique constraints). |
ForeignKeys | string | Foreign key definitions. |
Rows / RowsText / RowIdsCsv | IReadOnlyList<string> / string | Row-level entries for field-level (row) connections, plus their CSV of row ids. |
FromTableInfo(TableInfo) | static ERDEntity | Builds an entity from parsed DDL metadata. |
Each row entry carries Text, DataType, IsPrimaryKey, IsForeignKey and IsNullable, which drives the row-level connection points used for field-level relationships (see the Connection System).
DDL Export
DDLExporter turns entities into CREATE TABLE statements, including columns, primary keys, indexes and foreign keys:
var exporter = new DDLExporter(DDLImporter.SQLDialect.PostgreSQL);
// One entity
string createTable = exporter.ExportEntity(orderEntity);
// A whole diagram (topologically ordered so referenced tables come first)
var allEntities = drawingManager.GetComponents().OfType<ERDEntity>();
string script = exporter.ExportEntities(allEntities);
File.WriteAllText("schema.sql", script);
DDL Import
DDLImporter parses DDL text into TableInfo records (TableName, SchemaName, Columns, Constraints) or directly into entities you can add to the canvas. Dialects: ANSI, SQLServer, PostgreSQL, MySQL, Oracle, SQLite.
var importer = new DDLImporter(DDLImporter.SQLDialect.SQLServer);
// Parse only: metadata for inspection or comparison
List<DDLImporter.TableInfo> tables = importer.Parse(File.ReadAllText("schema.sql"));
// Or go straight to canvas entities
List<ERDEntity> entities = importer.ImportToEntities(ddlText, DDLImporter.SQLDialect.SQLServer);
float x = 60, y = 60;
foreach (var entity in entities)
{
entity.X = x;
entity.Y = y;
drawingManager.AddComponent(entity);
x += 260;
if (x > 1200) { x = 60; y += 320; }
}
drawingManager.RequestRedraw();
Schema Comparison
SchemaComparer.Compare(source, target) reports the changes needed to migrate source to target. Tables and columns match case-insensitively, duplicate table definitions do not throw, and the result groups changes by kind:
var comparer = new SchemaComparer();
SchemaComparisonResult diff = comparer.Compare(sourceTables, targetTables);
Console.WriteLine(diff.Summary()); // human-readable overview
Console.WriteLine(diff.HasChanges); // false when the schemas match
foreach (var change in diff.OfKind(SchemaChangeKind.AddedColumn))
Console.WriteLine($"{change.TableName}.{change.Column?.Name}");
foreach (var change in diff.OfKind(SchemaChangeKind.AlteredColumn))
Console.WriteLine($"{change.TableName}.{change.Column?.Name}: " +
$"{change.PreviousColumn?.DataType} -> {change.Column?.DataType}");
The comparison covers added and removed tables (AddedTable, RemovedTable), added and removed columns, altered columns (type, nullability, defaults), and constraint differences reported as foreign keys or table constraints. Each SchemaChange carries the table, the current and previous ColumnInfo/TableInfo, and the ConstraintInfo involved.
Migration Scripts
MigrationScriptGenerator turns a comparison result into executable SQL for both directions, in any supported dialect:
var generator = new MigrationScriptGenerator();
string forward = generator.GenerateForward(diff, DDLImporter.SQLDialect.PostgreSQL);
File.WriteAllText("migrate_up.sql", forward);
string rollback = generator.GenerateRollback(diff, DDLImporter.SQLDialect.PostgreSQL);
File.WriteAllText("migrate_down.sql", rollback);
Full Round-Trip: Database to Database
// 1. Capture both schemas as DDL (from your own tooling) and parse them
var importer = new DDLImporter(DDLImporter.SQLDialect.PostgreSQL);
var source = importer.Parse(sourceDdl);
var target = importer.Parse(targetDdl);
// 2. Compare and generate the migration
var diff = new SchemaComparer().Compare(source, target);
var sql = new MigrationScriptGenerator().GenerateForward(diff, DDLImporter.SQLDialect.PostgreSQL);
// 3. Review, then run
Console.WriteLine(diff.Summary());
Console.WriteLine(sql);
Review Before Running
Generated scripts are only as good as the parsed DDL. Treat the forward and rollback output as a reviewed artifact: back up first, and verify destructive changes (dropped columns, narrowed types) before executing.