Problem: The circle indicator (O) for optional relationships on the "one" side was not appearing, even though nullable foreign keys existed in the schema (e.g., Order.BillingAddressId, Customer.PreferredShippingAddressId).
Root Cause: The analyzeRelationshipCardinality() function was only checking if the FK itself was nullable to determine the "from" side optionality, but wasn't properly propagating that information to the "to" side (the "one" side of the relationship).
Fix:
- Updated
analyzeRelationshipCardinality()to properly detect when a nullable FK means the "one" side is optional (0..1) - The
toOptionalflag now correctly identifies relationships likeOrder -> Address?where the address is optional - Added proper logging to show both
fromOptionalandtoOptionaldetection
Example:
Order.BillingAddressId (int?)?Addressnow correctly showsO|on the Address sideCustomer.PreferredShippingAddressId (int?)?Addressnow correctly showsO|on the Address side
Problem: When no table was selected, the crow's foot notation appeared in a different blue shade than the relationship lines, creating visual inconsistency.
Root Cause: The color was hardcoded in the drawCrowsFootNotation() function but wasn't synchronized with the relationship line styling.
Fix:
- Ensured crow's foot notation uses the exact same blue color (
#2563eb) as relationship lines - Added proper color inheritance when relationships are highlighted (purple) or dimmed (gray)
- Updated dark mode colors to match relationship line dark mode styling
Visual Result:
- Default state: Crow's feet and lines both use consistent blue (
#2563eb) - Selected state: Crow's feet and lines both use purple (
#764ba2) - Dimmed state: Crow's feet and lines both use gray (
#d1d5db)
- Templates/relationships.js
drawCrowsFootNotation(): Added constants for circle drawing, improved logginganalyzeRelationshipCardinality(): Fixed optional relationship detection on "one" sideupdateRelationships(): Re-analyzes relationships when updating to ensure optional indicators persist
Test with schemas that have:
- ? Nullable FKs (e.g.,
Order.BillingAddressId?) - ? Self-referencing nullable FKs (e.g.,
Category.ParentCategoryId?) - ? Multiple optional relationships from same entity
- ? Mix of required and optional relationships
Perfect test schema with these relationships:
Order -> Customer(required, 1:N) ? Shows>|and|Order -> Address?via BillingAddressId (optional, 0..1:N) ? Shows>?and|?Order -> Address?via ShippingAddressId (optional, 0..1:N) ? Shows>?and|?Order -> Customer?via ApprovedById (optional, 0..1:N) ? Shows>?and|?Customer -> Address?via PreferredShippingAddressId (optional, 0..1) ? Shows|?and|?Category -> Category?via ParentCategoryId (optional, self-ref) ? Shows>?and|?
| Notation | Meaning | Example |
|---|---|---|
| `> | ` | Many (required) |
>? |
Many (optional) | N/A (uncommon - FK would be nullable) |
| |
One (required) | Order ? Customer (order must have customer) |
|? or O| |
One (optional) | Order ? Address? (order may not have address yet) |
For Order -> Address? (optional address):
- Order side:
>(many orders can reference same address) - Address side:
|?(one address, but optional - order may not have one)
For Customer -> Order (required customer):
- Customer side:
|(one customer per order) - Order side:
>(many orders per customer)
// From side (FK table) = many side
fromOptional = FK is nullable (int? or string?)
// To side (PK table) = one side
toOptional = FK is nullable (means the reference is optional)public class Order {
public int? BillingAddressId { get; set; } // Nullable FK
public Address? BillingAddress { get; set; } // Nullable navigation
}Analysis:
- FK is nullable ?
fromOptional = true? Order side shows circle - FK is nullable ?
toOptional = true? Address side shows circle - Result:
O>----|O(both sides optional)
All crow's foot notation colors properly support dark mode:
- Light mode:
#2563eb(blue) - Dark mode:
#60a5fa(lighter blue) - Highlighted: Matches selection overlay purple
- Dimmed: Matches dimmed relationship gray
- Circle size is fixed at 10px radius - may need adjustment for very small/large zoom levels
- Self-referencing optional relationships work correctly but may overlap if layout is tight
- Multiple optional relationships to same entity may have crowded notation
- Add tooltip showing relationship type when hovering crow's feet
- Support M:N relationships with different notation
- Add animation when relationships are highlighted/dimmed
- Configurable crow's foot size based on zoom level