Amazing ER
A library providing rich features around ER modelling. With this project, you could:
- Create ER schemas using Java
- Export ER schemas to JSON format
- Automatically define the layout of the ER diagram
- Transform ER schema to relational schema and generate Data Definition Language (DDL)
- Reverse engineering a database into an ER schema
- Round-trip for database modelling (synchronise the changes to database)
- Embed this project into your own application
Quick Start
How to use
This is the one of the sub-projects, the other two projects links:
Front-end application link: https://gitlab.doc.ic.ac.uk/bz2818/er-frontend
Back-end application link: https://gitlab.doc.ic.ac.uk/bz2818/er-backend
Their details are placed in their own README files.
The following diagram shows the structure of the three sub-projects:
Download the ER API sub-project using the following command line:
git clone https://gitlab.doc.ic.ac.uk/bz2818/er-api.git
After downloading the ER API subproject, you can package it into a JAR file and embed it in your own application.
The back-end application already contains the JAR file and can be used directly.
Examples
Create vanilla ER schema, export to JSON, image and DDL.
import io.github.MigadaTang.ER;
import io.github.MigadaTang.Entity;
import io.github.MigadaTang.Relationship;
import io.github.MigadaTang.Schema;
import io.github.MigadaTang.common.Cardinality;
import io.github.MigadaTang.common.DataType;
import java.io.IOException;
import java.sql.SQLException;
public class Example {
public static void main(String[] args) {
// initialize the in-memory database to store ER schema
ER.initialize();
// you could also specify your own database
// ER.initialize(RDBMSType.POSTGRESQL, "hostname", "port", "database", "user", "password");
Schema example = ER.createSchema("Vanilla");
Entity branch = example.addEntity("branch");
branch.addPrimaryKey("sortcode", DataType.INT);
branch.addAttribute("bname", DataType.VARCHAR, AttributeType.Mandatory);
branch.addAttribute("cash", DataType.DOUBLE, AttributeType.Mandatory);
Entity account = example.addEntity("account");
account.addPrimaryKey("no", DataType.INT);
account.addAttribute("type", DataType.CHAR, AttributeType.Mandatory);
account.addAttribute("cname", DataType.VARCHAR, AttributeType.Mandatory);
account.addAttribute("rate", DataType.DOUBLE, AttributeType.Mandatory);
Entity movement = example.addEntity("movement");
movement.addPrimaryKey("mid", DataType.INT);
movement.addAttribute("amount", DataType.DOUBLE, AttributeType.Mandatory);
movement.addAttribute("tdate", DataType.DATETIME, AttributeType.Mandatory);
Relationship holds = example.createRelationship("holds", account, branch, Cardinality.OneToOne, Cardinality.ZeroToMany);
Relationship has = example.createRelationship("has", account, movement, Cardinality.ZeroToMany, Cardinality.OneToOne);
// export the ER schema to a JSON format
String jsonString = example.toJSON();
// transform your ER schema to DDL
String DDL = example.generateSqlStatement();
}
}
Reverse engineering a database example
package io.github.MigadaTang;
import io.github.MigadaTang.common.RDBMSType;
import io.github.MigadaTang.exception.DBConnectionException;
import io.github.MigadaTang.exception.ParseException;
import io.github.MigadaTang.transform.Reverse;
import java.io.IOException;
import java.sql.SQLException;
public class Example {
public void reverseEngineer()
throws SQLException, ParseException, DBConnectionException, IOException {
ER.initialize();
Reverse reverse = new Reverse();
Schema schema = reverse.relationSchemasToERModel(RDBMSType.POSTGRESQL, "host"
, "port", "databaseName", "username", "password");
}
}
Round-trip case1 example:
package io.github.MigadaTang;
import io.github.MigadaTang.common.AttributeType;
import io.github.MigadaTang.common.Cardinality;
import io.github.MigadaTang.common.DataType;
import io.github.MigadaTang.exception.DBConnectionException;
import io.github.MigadaTang.exception.ParseException;
import java.io.IOException;
import java.sql.SQLException;
public class Example {
public void roundTripCase1()
throws SQLException, ParseException, DBConnectionException, IOException {
ER.initialize();
Schema schema = ER. createSchema("schemaName");
Entity entity1 = schema.addEntity("entityName1");
Entity entity2 = schema.addEntity("entityName2");
Attribute primaryKey1 = entity1 .addPrimaryKey("primaryKeyName1", DataType.TEXT);
Attribute attribute = entity1.addAttribute("attributeName", DataType.VARCHAR,
AttributeType.Mandatory ) ;
Attribute primaryKey2 = entity2 .addPrimaryKey("primaryKeyName2", DataType.TEXT);
Relationship relationship = schema.createRelationship("relationshipName",
entity1, entity2, Cardinality.OneToOne, Cardinality.ZeroToMany);
// Generate the DDL statements and execute them String
String DDL = schema.generateSqlStatement();
ER.connectToDatabaseAndExecuteSql("databaseType", "hostname",
"portNumber", "databaseName", "username", "password", DDL);
// Then continue editing the ER schema, such as adding new attribute in entity1
Attribute attribute2 = entity1.addAttribute("attributeName2", DataType.VARCHAR,
AttributeType.Mandatory ) ;
// Generate the corresponding SQL statements and execute them
String SQL = schema.generateSqlStatement();
ER.connectToDatabaseAndExecuteSql("databaseType", "hostname",
"portNumber", "databaseName", "username",
"password", SQL);
}
}
Round-trip case2 example:
package io.github.MigadaTang;
import io.github.MigadaTang.common.RDBMSType;
import io.github.MigadaTang.exception.DBConnectionException;
import io.github.MigadaTang.exception.ParseException;
import io.github.MigadaTang.transform.Reverse;
import java.io.IOException;
import java.sql.SQLException;
public class Example {
public void roundTripCase2()
throws SQLException, ParseException, DBConnectionException, IOException {
ER.initialize();
Reverse reverse = new Reverse ();
Schema schema = reverse .relationSchemasToERModel(RDBMSType.POSTGRESQL,
"hostname", "portNumber", "databaseName",
"username", "password");
// After make some modifications in the schema
String SQL = schema.generateSqlStatement();
// Execute the SQL statements in the database
ER.connectToDatabaseAndExecuteSql("databaseType", "hostname", "portNumber",
"databaseName", "username", "password", SQL);
}
}
ER schema to JSON
{
"name": "Vanilla",
"entityList": [
{
"name": "branch",
"entityType": "STRONG",
"attributeList": [
{
"name": "sortcode",
"dataType": "INT",
"isPrimary": true,
"attributeType": "Mandatory"
},
{
"name": "bname",
"dataType": "VARCHAR",
"isPrimary": false,
"attributeType": "Mandatory"
},
{
"name": "cash",
"dataType": "DOUBLE",
"isPrimary": false,
"attributeType": "Mandatory"
}
]
},
{
"name": "account",
"entityType": "STRONG",
"attributeList": [
{
"name": "no",
"dataType": "INT",
"isPrimary": true,
"attributeType": "Mandatory"
},
{
"name": "type",
"dataType": "CHAR",
"isPrimary": false,
"attributeType": "Mandatory"
},
{
"name": "cname",
"dataType": "VARCHAR",
"isPrimary": false,
"attributeType": "Mandatory"
},
{
"name": "rate",
"dataType": "DOUBLE",
"isPrimary": false,
"attributeType": "Mandatory"
}
]
},
{
"name": "movement",
"entityType": "STRONG",
"attributeList": [
{
"name": "mid",
"dataType": "INT",
"isPrimary": true,
"attributeType": "Mandatory"
},
{
"name": "amount",
"dataType": "DOUBLE",
"isPrimary": false,
"attributeType": "Mandatory"
},
{
"name": "tdate",
"dataType": "DATETIME",
"isPrimary": false,
"attributeType": "Mandatory"
}
]
}
],
"relationshipList": [
{
"name": "holds",
"edgeList": [
{
"entity": "account",
"cardinality": "1:1"
},
{
"entity": "branch",
"cardinality": "0:N"
}
]
},
{
"name": "has",
"edgeList": [
{
"entity": "account",
"cardinality": "0:N"
},
{
"entity": "movement",
"cardinality": "1:1"
}
]
}
]
}
ER schema to Data Definition Language(DDL)
CREATE TABLE `branch` (
`sortcode` INT NOT NULL,
`bname` VARCHAR NOT NULL,
`cash` DOUBLE NOT NULL,
CONSTRAINT branch_pk PRIMARY KEY (sortcode)
)
CREATE TABLE `account` (
`no` INT NOT NULL,
`type` CHAR NOT NULL,
`cname` VARCHAR NOT NULL,
`rate` DOUBLE NOT NULL,
`branch_sortcode` INT NOT NULL,
CONSTRAINT account_pk PRIMARY KEY (no),
CONSTRAINT account_fk1 FOREIGN KEY (branch_sortcode) REFERENCES branch(sortcode)
)
CREATE TABLE `movement` (
`mid` INT NOT NULL,
`amount` DOUBLE NOT NULL,
`tdate` DATETIME NOT NULL,
`account_no` INT NOT NULL,
CONSTRAINT movement_pk PRIMARY KEY (mid),
CONSTRAINT movement_fk1 FOREIGN KEY (account_no) REFERENCES account(no)
)
Create n-ary relationship
public class Example {
public static void main(String[] args) {
Schema example = ER.createSchema("N-ary Relationship");
Entity person = example.addEntity("person");
Entity manager = example.addEntity("manager");
Entity department = example.addEntity("department");
ArrayList<ConnObjWithCardinality> eCardList = new ArrayList<>();
eCardList.add(new ConnObjWithCardinality(person, Cardinality.ZeroToMany));
eCardList.add(new ConnObjWithCardinality(manager, Cardinality.ZeroToMany));
eCardList.add(new ConnObjWithCardinality(department, Cardinality.ZeroToMany));
Relationship worksIn = example.createNaryRelationship("works in", eCardList);
}
}
Create subset
public class Example {
public static void main(String[] args) {
Schema example = ER.createSchema("Subset");
Entity person = example.addEntity("person");
person.addPrimaryKey("salary number", DataType.VARCHAR);
person.addAttribute("bonus", DataType.VARCHAR, AttributeType.Optional);
person.addAttribute("name", DataType.VARCHAR, AttributeType.Mandatory);
Entity manager = example.addSubset("manager", person);
manager.addAttribute("mobile number", DataType.VARCHAR, AttributeType.Mandatory);
}
}
More examples
see TestQuickStartExamples and TestGenerateDDL
Documentation
More information about the classes and methods of this library can be found in Javadoc
ER Schema Extensions Supported
ER Extensions | Supported |
---|---|
Weak entities | ✅ |
N-ary relationships | ✅ |
Attributes on relationships | ✅ |
Nested relationships | ✅ |
Multi-valued Attributes | ✅ |
License
This code is under the MIT Licence.