UML: Class & Object Diagrams

From Class Diagram to Database & Code

18 min Lesson 9 of 10

From Class Diagram to Database & Code

A class diagram is not just documentation — it is a blueprint. Once your domain model is stable, you can mechanically translate it into two deliverables that developers care about most: a relational database schema and source-code class skeletons. Understanding this translation is one of the most practical skills a systems analyst can master, because it bridges the gap between analysis and implementation.

Why the Mapping Matters

Developers frequently receive a class diagram from analysts and must produce working code and a database from it. When the translation rules are applied consistently, the result is a schema whose tables mirror the domain, foreign keys that match associations, and class files whose fields and methods follow directly from the model. Errors in the mapping — such as ignoring multiplicity or missing an association class — are expensive to fix once data starts accumulating.

Rule 1 — Each Class Becomes a Table

Every concrete class in the diagram maps to a table. The class name becomes the table name (usually plural in practice). Each attribute becomes a column, and the UML type maps to a database type:

  • StringVARCHAR
  • IntegerINT
  • BooleanTINYINT(1) or BOOLEAN
  • Date / DateTimeDATE / DATETIME
  • DecimalDECIMAL(p,s)

Every table also gets a surrogate primary key (id) unless the model specifies a natural key. In code, the class becomes a file with private fields and getter/setter methods (or public properties depending on the language).

Rule 2 — Associations Become Foreign Keys

The multiplicity of an association determines exactly how the foreign key is placed:

  • One-to-Many (1 → 0..*) — the foreign key lives on the many side. For example, an Order belongs to one Customer: the orders table gets a customer_id column.
  • One-to-One (1 → 0..1) — the foreign key lives in the weaker/optional side. A Patient has one optional MedicalRecord: the medical_records table gets a patient_id (unique).
  • Many-to-Many (* → *) — a junction table is required. It has two foreign keys — one to each side — and its own primary key (or a composite one).

In code, a one-to-many association becomes a collection field on the one side (e.g., List<Order> orders) and a reference field on the many side (e.g., Customer customer).

Rule 3 — Aggregation and Composition

Aggregation maps the same way as a regular association — a foreign key on the part side (or a junction table for many-to-many). The distinction is semantic, not structural, in the database. In code, the "whole" class holds a reference or collection to the "part".

Composition signals a stronger ownership: the part cannot exist without the whole. In the database, add ON DELETE CASCADE to the foreign key so that deleting the whole automatically removes its parts. In code, the whole is responsible for creating and destroying its parts.

Rule 4 — Inheritance Strategies

Inheritance has three common mapping strategies in relational databases:

  1. Single Table Inheritance (STI) — one table for the entire hierarchy with a type discriminator column. Simple but wastes space with NULLs for subclass-specific columns.
  2. Class Table Inheritance (CTI) — one table per class in the hierarchy; the subclass table's primary key is also a foreign key to the parent table. Normalized but requires JOINs.
  3. Concrete Table Inheritance — one table per leaf class, with all parent attributes duplicated. Fast reads but data duplication.

In code, the class hierarchy maps directly: the parent class (or abstract class) is the base; subclasses extend it and inherit attributes and methods.

Class Diagram to Database and Code mapping for an online store Class Diagram Customer + id : Integer + name : String + email : String + placeOrder() : Order 1 0..* Order + id : Integer + date : DateTime + total : Decimal + confirm() : void + cancel() : void * * OrderItem + quantity : Integer + unitPrice : Decimal Product + id : Integer + name : String + price : Decimal + stock : Integer + getDetails() : String maps to Database Tables customers 🔑 id INT PK AUTO_INCREMENT name VARCHAR(255) email VARCHAR(255) UNIQUE created_at DATETIME orders 🔑 id INT PK 🔗 customer_id INT FK date DATETIME total DECIMAL(10,2) status VARCHAR(20) order_items 🔗 order_id INT FK 🔗 product_id INT FK quantity INT unit_price DECIMAL(10,2) 🔑 = Primary Key 🔗 = Foreign Key
An online store class diagram (left) mapped to relational database tables (right). The many-to-many Order–Product association becomes the order_items junction table.

Rule 5 — Association Classes Become Junction Tables

When a many-to-many relationship carries its own attributes (an association class), those attributes become columns in the junction table. In the diagram above, OrderItem holds quantity and unitPrice: these become columns in the order_items table alongside the two foreign keys.

Rule 6 — Abstract Classes and Interfaces

Abstract classes do not get their own table when using Concrete Table Inheritance, but do get one in Class Table Inheritance. Interfaces have no database mapping — they are a code-only concept. In code, abstract classes become abstract class declarations; interfaces become interface declarations with method signatures and no implementation bodies.

Inheritance mapped to Class Table Inheritance (CTI) database strategy Class Diagram (Inheritance) «abstract» Payment + id : Integer + amount : Decimal + process() : Boolean CardPayment + cardNumber : String + expiry : String CashPayment + receivedAmount : Decimal + changeGiven : Decimal CTI strategy Database (CTI) payments 🔑 id INT PK amount DECIMAL(10,2) type VARCHAR(20) card_payments 🔗 id INT PK+FK → payments card_number VARCHAR(20) expiry VARCHAR(7) cash_pmts 🔗 id FK received change CTI: each subclass gets its own table. Sub-table PK is also a FK to the parent.
The Payment class hierarchy mapped using Class Table Inheritance (CTI): one table per class, with the subclass table's primary key doubling as a foreign key to the parent payments table.

Code Skeleton Example

Translating to code is equally mechanical. Consider the Order class from the online store. A typical object-oriented skeleton looks like this:

// Java-style skeleton derived from the class diagram public class Order { private int id; private Customer customer; // association → reference field private List<OrderItem> items; // composition → collection private LocalDateTime date; private BigDecimal total; private String status; public Order(Customer customer) { this.customer = customer; this.items = new ArrayList<>(); this.date = LocalDateTime.now(); this.status = "PENDING"; } public void confirm() { this.status = "CONFIRMED"; } public void cancel() { this.status = "CANCELLED"; } public BigDecimal getTotal() { return this.total; } }

Notice how each UML attribute becomes a private field, each association becomes a reference or collection, and each UML operation becomes a method. The constructor enforces the mandatory association (an Order must have a Customer).

Analyst Tip — Stop at the Boundary. Your job as a systems analyst is to produce a correct, complete class diagram. Developers own the code-generation step. However, knowing the translation rules helps you catch errors early: if you cannot map your diagram to tables cleanly, the model itself may have a flaw — a missing multiplicity, a misplaced association, or an unnecessary class.
Naming Conventions Matter. Use PascalCase for class names and camelCase for attributes and operations in UML. When generating tables, convert to snake_case (e.g., OrderItemorder_items). Consistent naming avoids confusion between the model and the implementation.
Do Not Flatten Composition into Attributes. A common mistake is to represent a composed part (like an Address inside a Customer) as a bag of string attributes on the parent class. This breaks normalization and hides the structure. Model it as a separate class, then decide in the database whether to give it its own table or embed it as columns (an acceptable trade-off for simple value objects, but make it a conscious choice).

Checklist: Class Diagram to Database

  1. Every concrete class → one table.
  2. Every attribute → one column (with the correct SQL type).
  3. One-to-many association → FK on the many-side table.
  4. Many-to-many association (with or without association class) → junction table with two FKs.
  5. Composition → add ON DELETE CASCADE to the FK.
  6. Inheritance → choose STI, CTI, or Concrete Table and apply consistently.
  7. Abstract classes → table only in CTI (holds shared columns).
  8. Interfaces → no table, no columns — code only.

With these rules in hand, you can hand a developer a class diagram and a mapping decision sheet, and they will be able to build a correct database and code structure without guessing. That precision is the hallmark of a professional systems analyst.