2. Logical Data Model
Add attributes, primary keys, and foreign keys — still database-agnostic, but fully detailed.
What is a Logical Data Model?
The Logical Data Model (LDM) is your CDM with all the details added:
- Attributes — what data each entity actually stores
- Primary keys — what uniquely identifies each row
- Foreign keys — explicit references between tables
- Data types in abstract form — "Text", "Money", "Date" (no VARCHAR/DECIMAL yet)
- Cardinality and optionality — fully specified
- Normalization — typically to 3NF
The LDM is still database-agnostic. You haven't picked Oracle vs MySQL vs Postgres yet. The audience is data architects and designers.
Starting from the CDM
If you saved your CDM file, open it. We'll add attributes and resolve the many-to-many relationship.
Switch to Logical display mode
Make sure you're in Logical view:
The entities now show separator lines for attributes (currently empty). They look like:
Add attributes to Customer
Double-click the Customer entity to open the Property Editor. Click the Attributes tab.
Click New to add each attribute:
- Customer ID — check the Primary Key checkbox; datatype = Number
- First Name — datatype = String
- Last Name — datatype = String
- Email — datatype = String; check Unique alternate key
- Phone — datatype = String; optional (don't check Not Null)
- Created Date — datatype = Datetime
Click OK. The Customer entity now shows all six attributes, with "Customer ID" above the divider line (because it's the PK) and the others below.
Why the divider line matters
ERWIN entities have a horizontal line splitting them into two zones:
Above the line
Primary key attributes. These uniquely identify each row.
Below the line
Non-key attributes — all the descriptive data.
Foreign keys appear below the line marked with (FK) after the attribute name. Identifying-relationship FKs go above the line (because they're part of the child's PK).
Add attributes to all other entities
Repeat for each entity. Suggested attributes:
Address
- Address ID — PK, Number
- Street Line 1 — String
- Street Line 2 — String, optional
- City — String
- State — String
- Postal Code — String
- Country — String
- Address Type — String ("Shipping", "Billing")
Category
- Category ID — PK, Number
- Category Name — String, Unique
- Description — String, optional
Product
- Product ID — PK, Number
- Product Name — String
- SKU — String, Unique
- Unit Price — Money
- Stock Quantity — Number
- Active — Boolean
Order
- Order ID — PK, Number
- Order Date — Datetime
- Order Status — String ("Pending", "Shipped", "Delivered", "Cancelled")
- Total Amount — Money
Foreign keys propagate automatically
Look at the Order entity now. It should automatically show:
- Customer ID (FK) — propagated from the Customer → Order relationship
- Address ID (FK) — propagated from the Order → Address relationship (shipping address)
You didn't have to add these manually. This is the magic of ERWIN: when you draw a relationship, the parent's PK automatically appears in the child as an FK. Move the relationship, the FK moves. Rename the PK, the FK renames everywhere.
Resolve the many-to-many Order ↔ Product
Right-click the M:N relationship line between Order and Product. Choose Convert to Associative Entity (older versions: "Resolve M:N").
ERWIN inserts a new entity between Order and Product, with two 1:N relationships pointing in. By default it's called "Order_Product" — rename it to Order Line (or "Order Item" / "Line Item" — whatever your business calls it).
Add attributes to Order Line:
- Order Line ID — PK, Number (this is the standalone PK)
- Quantity — Number
- Unit Price At Time Of Order — Money
- Line Total — Money
- Order ID (FK) — already there from migration
- Product ID (FK) — already there from migration
Use domains for consistent data types
You'll notice you've been typing "String" and "Money" repeatedly. ERWIN's Domains let you define these once and reuse them.
Common domains to create:
- Money — Decimal, precision 18, scale 4
- ShortText — String, length 50
- LongText — String, length 500
- ID — Big Integer, identity/auto-increment
- AuditTimestamp — Datetime, default current_timestamp
Now when adding new attributes, you can pick the domain instead of typing a type. Change the domain definition once and every attribute using it updates automatically.
Set Not Null and check constraints
Reopen Property Editor for each entity. For each attribute, set:
- Not Null — for fields that must always have a value (PKs, names, emails)
- Check constraint — for fields with valid values (e.g., Order Status IN ('Pending','Shipped','Delivered','Cancelled'))
- Default value — sensible defaults (Active = true, Created Date = current_timestamp)
These constraints will translate to SQL CHECK constraints in the physical model.
Validate the model
ERWIN can check your model for common problems:
It'll flag:
- Entities without primary keys
- Relationships without verb phrases
- Attributes without data types
- Missing definitions on entities
- Naming convention violations (we'll set up rules in the Physical lesson)
Fix anything flagged, save your work as ecommerce_logical.erwin, and you've completed a proper logical data model.
What our LDM looks like now
Normalization check
Walk through 1NF, 2NF, 3NF:
- 1NF ✓ Every column holds a single atomic value
- 2NF ✓ Every non-key attribute depends on the full PK (we used single-column surrogate PKs, so this is automatic)
- 3NF ✓ No non-key attribute depends on another non-key attribute (we put Category in its own table, not inline on Product)
If you find a 3NF violation (e.g., Customer.City and Customer.State, where State depends on City), break it into a separate lookup entity.