Skip to content

Relationships & crow's foot notation โ€‹

Every Ref: declaration in your schema becomes a line in the diagram, connecting the source field to the target field. The shape of the line tells you which two fields are related; the symbols at each end tell you the cardinality and optionality of that relationship.

๐Ÿ“ธ Screenshot placeholder

[Screenshot needed] Filename suggestion: relationships-overview.png Caption: A diagram with three relationships visible, demonstrating different cardinalities. Should show: a small schema (e.g. blog or e-commerce) with three or four relationship lines visible, showing a mix of crow's foot variants at the endpoints (one-to-many, many-to-many, and one-or-zero). Cardinality text labels visible next to each endpoint.

Crow's foot symbols โ€‹

Crow's foot notation has been the standard for ER diagrams since the 1980s. The vocabulary is small. Each endpoint of a relationship line carries one of four symbols, built from three primitives:

Exactly onemin=1, max=1 (mandatory, single)Zero or onemin=0, max=1 (optional, exclusive)One or manymin=1, max=* (mandatory, multiple)Zero or manymin=0, max=* (optional, multiple)

The three primitives compose into the four standard cases:

  • A bar (โ•‘) caps the line for "exactly one" cardinality.
  • A ring (โ—‹) marks "zero is allowed" (optional participation).
  • A crow's foot (โ‰บ) marks "many" cardinality, with the V opening toward the related entity.

Combining them gives:

  • Bar alone: exactly one. Mandatory, single.
  • Ring + bar: zero or one. Optional, exclusive.
  • Crow's foot alone: one or many. Mandatory, multiple.
  • Ring + crow's foot: zero or many. Optional, multiple.

The ring always sits closer to the line, the bar or crow's foot at the line's end. The relationship is read by looking at each endpoint independently: "at this end, how many of this entity participate?"

Where the cardinality comes from โ€‹

xDBML has two ways to express cardinality, and the diagram uses whichever is present:

Explicit settings override everything else:

xdbml
Ref: orders.customer_id > customers.id [source: '0..*', target: '1..1']

The strings are UML-style min..max. 0 means optional, 1 means mandatory minimum, * means unbounded maximum. The diagram parses these and picks the matching glyph at each end.

Operator shorthand is the default when no explicit cardinality is given:

xdbml
Ref: orders.customer_id > customers.id

The four operators map to defaults:

OperatorMeaningSourceTarget
>many-to-one1..*1..1
<one-to-many1..11..*
-one-to-one1..11..1
<>many-to-many0..*0..*

Optional ends. Two things make an end optional, which draws its ring:

  • A ? written against the operator, as in DBML: >? makes the target end optional, ?< the source end, ?-? both. The end keeps its maximum, so >? gives 1..* and 0..1.
  • A foreign key that may hold null makes the parent end optional, since a child whose foreign key is null has no parent. A field is nullable when it lacks not null and belongs to no primary key.
xdbml
Entity orders {
  id          int [pk]
  customer_id int                 // nullable
  store_id    int [not null]
}

Ref: orders.customer_id > customers.id   // 1..* and 0..1: an order may have no customer
Ref: orders.store_id > stores.id         // 1..* and 1..1

A setting states its end outright, whatever the operator, its marks and the foreign key say. When a ? and a setting disagree on an end, the diagnostics panel shows a warning: in a document declaring an xdbml: version the setting applies, and in one without, which reads as DBML, the ? applies. Tools that write xDBML state cardinality with settings and write no marks.

Select the relationship to see where each end's range comes from: the inspector's Cardinality section names the setting, the operator, the mark or the nullable foreign key.

Non-standard cardinalities โ€‹

xDBML accepts non-standard cardinalities like [source: '2..5'] (between 2 and 5 instances). The crow's foot symbol can only approximate this; for the example above, the diagram draws a "one or many" glyph (1..*), since "between 2 and 5" is closer to that than to "exactly one" or "zero or one."

The exact text is shown alongside the glyph as a small label, so the precise value isn't lost. For non-standard cardinalities, the text is the source of truth and the glyph is a visual hint.

The line itself โ€‹

Relationship lines are drawn with horizontal and vertical segments only. The path is chosen to:

  • Leave and enter each entity card on the side that faces the other endpoint
  • Anchor at the vertical midpoint of the source or target field's row, when the endpoint names a field
  • Turn at right angles, which keeps crossings legible on a busy diagram

The path is purely visual. The meaning is in the two endpoints and the symbols at each end.

Relationship types and line styles โ€‹

The line style tells you what kind of relationship it is:

LineRelationshipWritten as
SolidForeign key (referential)Ref: orders.customer_id > customers.id
DottedForeign master (denormalized replication)Ref: orders.customer_name > customers.name [foreign_master]
Small open circlesInactive, of either kind[inactive] on the Ref

A foreign master records that the child attribute holds a copy of the parent's value, as document models often do. Nothing is generated from it; it documents where the copy comes from.

Each endpoint field also gets a marker badge, so you can tell a field's role without following the line:

  • fk on the child side and dk on the parent side of a foreign key
  • fm on the child side and dm on the parent side of a foreign master

A field that is the parent of both kinds shows dk and dm side by side. See Entity cards for the other badges.

Conceptual relationships โ€‹

In a conceptual or early logical model, a relationship may name entities rather than fields:

xdbml
Entity Customer { }
Entity Order { }

Ref: Customer > Order [source_verb: 'places']

The line then attaches to the edge of each card that faces the other card, not to a field row. It shows no cardinality glyph until a cardinality is written with [source: ..., target: ...]. A small filled triangle marks the direction it reads: > puts the triangle at the target, < at the source, undirected: true at both ends, and - nowhere, meaning linked with no direction stated.

A relationship to a subtype of a supertype group is written this way too, since a subtype declares only its own attributes: Ref: Assignment.employee_id > Employee.

Roles, verbs and constraint type โ€‹

A relationship can also carry the wording a conceptual or logical model reads it with, and whether the child depends on its parent for its identity. None of this changes how the line is drawn. Select the line and the inspector shows it.

Roles and verbs โ€‹

A relationship reads in two directions, and each direction has its own wording. In "a Customer plays the role of buyer and places zero or more Orders", buyer is a role and places is a verb. Read the other way: "an Order is a shopping cart that is bought by exactly one Customer". A role belongs to the entity at one end; a verb belongs to a reading direction. Four settings carry them:

xdbml
Ref places: orders.customer_id > customers.id [
  source_role: 'shopping cart', source_verb: 'is bought by',
  target_role: 'buyer',         target_verb: 'places',
  source: '0..*',               target: '1..1'
]

source_verb reads from the source toward the target, and target_verb from the target toward the source. The two are usually converses of each other, and nothing checks that; you may state one, both, or neither. In the inspector, the Reading section lists the roles, verbs and cardinalities and reads them back as sentences, one per direction.

Roles and verbs are documentation: nothing is generated from them. They work the same on an entity-level relationship, which is where a conceptual model usually needs them.

Identifying and non-identifying โ€‹

A foreign key relationship is identifying when the child's foreign key attributes are part of the child's primary key: an order line cannot be identified without its order. It is non-identifying when the child stands on its own and merely points at its parent: an order points at its customer.

xdbml
Ref: order_lines.order_id > orders.id [constraint_type: identifying]
Ref: orders.customer_id > customers.id [constraint_type: non_identifying]

The setting records the modeler's intent. It adds no key and checks none, so it can be stated before the child has a primary key, or any attributes at all. Leaving it out means the constraint type is not stated yet, which is different from non_identifying. It applies to foreign keys only: a foreign master has no key dependency, and a many-to-many relationship has no single child. On a foreign master it is reported as an error.

The diagram draws identifying and non-identifying relationships the same way. The inspector shows the value as Constraint.

Relationship names โ€‹

A named relationship (Ref places: ...) can show its name at the middle of its line. Turn on Display > Relationship names in the diagram toolbar; the option is off by default and also shows the names of supertype groups.

Showing and hiding relationships โ€‹

The Display menu in the diagram toolbar has a checkbox per kind: Foreign key, Foreign master, Inactive, Conceptual and Supertype groups, Sticky notes under Annotations, Dependencies under Lineage for the curves of data lineage (see Visual cues), and Relationship names under Labels. The choices are remembered between sessions. When a relationship kind is hidden, the Display button is highlighted so you know something is off screen.

Selection โ€‹

Clicking on a relationship line selects it. The line and both endpoint glyphs turn blue and the stroke thickens. The inspector pane opens showing the operator, source and target, the name if there is one, the relationship type (foreign key or foreign master), the reading direction, the constraint type (identifying or non-identifying) when stated, and a Reading section with the roles, verbs and cardinalities, read back as sentences. See Inspector pane.

The hit area for clicking is wider than the visible line, since the visible 1.5-pixel line would be hard to target precisely. You can click within a few pixels of the line and it counts as a click on the line.

What if I want a different notation? โ€‹

The playground uses crow's foot notation for relationships and the half-circle for supertype groups. Other ERD notations (Chen, Bachman, UML's filled-and-open-arrows) are not currently supported. If you'd find them useful, open an issue and we'll track interest.

What's next โ€‹

Spec under Apache License 2.0 ยท Examples under CC0 1.0