|
| 1 | +# SchemaMagic Updates - January 5, 2025 |
| 2 | + |
| 3 | +## ?? Overview |
| 4 | +This update improves relationship visualization in SchemaMagic with better handling of nullable foreign keys (0..1 relationships) and cleaner rendering of self-referential and vertically stacked table relationships. |
| 5 | + |
| 6 | +## ? Key Improvements |
| 7 | + |
| 8 | +### 1. Enhanced 0..1 Relationship Demonstrations |
| 9 | +All sample DbContext files now include examples of **optional (nullable) foreign key relationships** to showcase the `0..1` relationship symbol: |
| 10 | + |
| 11 | +#### **ECommerceDbContext.cs** |
| 12 | +- ? `Order.BillingAddressId` (nullable) - Orders may not have billing address yet |
| 13 | +- ? `Order.ShippingAddressId` (nullable) - Digital orders may not need shipping |
| 14 | +- ? `Order.ApprovedById` (nullable) - Orders may not be approved yet |
| 15 | +- ? `Customer.PreferredShippingAddressId` (nullable) - Customers may not have a preferred address |
| 16 | +- ? `Category.ParentCategoryId` (nullable) - Self-referential hierarchy |
| 17 | + |
| 18 | +#### **BlogDbContext.cs** |
| 19 | +- ? `Post.ReviewedById` (nullable) - Posts may not be reviewed yet |
| 20 | + |
| 21 | +#### **SimpleTestDbContext.cs** |
| 22 | +- ? `Company.PrimaryContactId` (nullable) - New companies may not have a primary contact yet |
| 23 | +- ? `User.ManagerId` (nullable) - Top-level users don't have managers (self-referential hierarchy) |
| 24 | + |
| 25 | +### 2. Fixed Self-Referential Relationship Rendering ?? |
| 26 | +**Problem**: Self-referential relationships (e.g., `Category.ParentCategoryId ? Category.Id`) had a "weird tail" with unnecessary intermediate path segments. |
| 27 | + |
| 28 | +**Solution**: Simplified the path calculation to create a clean rectangular loop: |
| 29 | +- Exit from the left edge of the FK property |
| 30 | +- Move left by a fixed distance (200px) |
| 31 | +- Move vertically to the target row (Id property) |
| 32 | +- Enter back at the left edge |
| 33 | + |
| 34 | +**Before**: |
| 35 | +```javascript |
| 36 | +// Complex path with unnecessary midpoint calculation |
| 37 | +const midY = fromY + ((toY - fromY) / 2) + SELF_REF_LOOP_HEIGHT; |
| 38 | +pathSegments = [M, L loopLeft, L midY, L toY, L target]; // 5 segments with weird tail |
| 39 | +``` |
| 40 | + |
| 41 | +**After**: |
| 42 | +```javascript |
| 43 | +// Clean rectangular path |
| 44 | +pathSegments = [ |
| 45 | + M fromX fromY, // Start at FK |
| 46 | + L loopLeft fromY, // Go left |
| 47 | + L loopLeft toY, // Go vertically |
| 48 | + L toX toY // Enter at Id |
| 49 | +]; // 4 segments, clean loop |
| 50 | +``` |
| 51 | + |
| 52 | +### 3. Improved Vertical Stacking Routing ?? |
| 53 | +**Problem**: When tables are stacked vertically (large vertical separation), relationship lines used long horizontal segments that looked unnatural. |
| 54 | + |
| 55 | +**Solution**: Implemented **angled routing** for vertically separated tables: |
| 56 | + |
| 57 | +#### Detection Logic |
| 58 | +```javascript |
| 59 | +const verticalSeparation = Math.abs(fromY - toY); |
| 60 | +const horizontalSeparation = toX - fromX; // or fromX - toX |
| 61 | + |
| 62 | +if (verticalSeparation > 100 && horizontalSeparation > 100) { |
| 63 | + // Use angled routing |
| 64 | +} |
| 65 | +``` |
| 66 | + |
| 67 | +#### Angled Path Pattern (LEFT?RIGHT example) |
| 68 | +```javascript |
| 69 | +const midX = fromX + (horizontalSeparation * 0.4); // 40% of the way |
| 70 | + |
| 71 | +pathSegments = [ |
| 72 | + M fromX fromY, // Start at FK on right edge |
| 73 | + L midX fromY, // Move right 40% of the way |
| 74 | + L midX toY, // Angle vertically to target row |
| 75 | + L entryX toY, // Move horizontal toward target |
| 76 | + L toX toY // Enter at left edge |
| 77 | +]; |
| 78 | +``` |
| 79 | + |
| 80 | +**Visual Result**: |
| 81 | +``` |
| 82 | +OrderItem (left, top) ? Product (right, bottom) |
| 83 | +
|
| 84 | +[OrderItem]??????? |
| 85 | + ProductId ? (exit right, move 40% horizontally) |
| 86 | + ? |
| 87 | + ? (angle down) |
| 88 | + ? |
| 89 | + ??????? [Product] |
| 90 | + Id |
| 91 | +``` |
| 92 | + |
| 93 | +This creates a more natural flow that follows the visual hierarchy of the schema. |
| 94 | + |
| 95 | +### 4. Updated Both Path Functions |
| 96 | +Both `createCrowsFootRelationshipLine()` and `updateRelationships()` now use the same improved routing logic to ensure consistency when: |
| 97 | +- Tables are initially rendered |
| 98 | +- Tables are dragged to new positions |
| 99 | +- The view is zoomed or panned |
| 100 | + |
| 101 | +## ?? Testing Recommendations |
| 102 | + |
| 103 | +### Test Self-Referential Relationships |
| 104 | +1. Generate schema from `ECommerceDbContext.cs` |
| 105 | +2. Verify `Category.ParentCategoryId ? Category` has a clean rectangular loop on the left side |
| 106 | +3. No "weird tail" or extra path segments |
| 107 | + |
| 108 | +### Test 0..1 Relationships |
| 109 | +1. Generate schema from any sample DbContext |
| 110 | +2. Look for nullable FK properties (marked with `?` in the type) |
| 111 | +3. Verify the relationship line shows the optional circle marker at the FK side |
| 112 | +4. Marker should be: `url(#many-optional-side)` or `url(#one-optional-side)` |
| 113 | + |
| 114 | +### Test Vertical Stacking |
| 115 | +1. Generate schema from `ECommerceDbContext.cs` |
| 116 | +2. Drag `OrderItem` to the top-left and `Product` to the bottom-right |
| 117 | +3. Verify the `OrderItem.ProductId ? Product.Id` relationship uses angled routing |
| 118 | +4. Path should exit right, move partway, angle down, then move horizontal to target |
| 119 | + |
| 120 | +### Test Standard Horizontal Layout |
| 121 | +1. Place tables side-by-side at similar vertical levels |
| 122 | +2. Verify routing still uses the standard horizontal path with marker offsets |
| 123 | +3. No unnecessary intermediate angles when tables are horizontally aligned |
| 124 | + |
| 125 | +## ?? Files Modified |
| 126 | + |
| 127 | +### Sample DbContext Files |
| 128 | +- ? `Samples/ECommerceDbContext.cs` - Added 4 new nullable FKs |
| 129 | +- ? `Samples/BlogDbContext.cs` - Added 1 new nullable FK |
| 130 | +- ? `SimpleTestDbContext.cs` - Added 1 new nullable FK |
| 131 | + |
| 132 | +### Template JavaScript Files |
| 133 | +- ? `Templates/relationships.js` |
| 134 | + - Simplified self-referential loop path (lines 117-137) |
| 135 | + - Added angled routing for vertical separation (lines 138-175) |
| 136 | + - Updated `updateRelationships()` with same logic (lines 405-480) |
| 137 | + |
| 138 | +## ?? Visual Improvements Summary |
| 139 | + |
| 140 | +| Scenario | Before | After | |
| 141 | +|----------|--------|-------| |
| 142 | +| Self-referential | Complex loop with "tail" | Clean rectangular loop | |
| 143 | +| Vertical stacking | Long horizontal lines | Natural angled routing | |
| 144 | +| 0..1 relationships | Not well demonstrated | Multiple examples in samples | |
| 145 | +| Optional markers | Few examples | Visible in 7+ relationships | |
| 146 | + |
| 147 | +## ?? Next Steps |
| 148 | + |
| 149 | +### For Users |
| 150 | +1. Test the updated routing with your own DbContext files |
| 151 | +2. Provide feedback on the angled routing behavior |
| 152 | +3. Report any edge cases where routing looks incorrect |
| 153 | + |
| 154 | +### For Development |
| 155 | +1. Consider making the angle percentage (currently 40%) configurable |
| 156 | +2. Add user preference for routing style (angled vs. orthogonal) |
| 157 | +3. Implement automatic layout optimization based on relationship density |
| 158 | +4. Add smooth path transitions when dragging tables |
| 159 | + |
| 160 | +## ?? Notes |
| 161 | + |
| 162 | +- All changes are backward compatible |
| 163 | +- Generated HTML files include the updated JavaScript |
| 164 | +- Routing calculations happen in real-time as tables are moved |
| 165 | +- The 100px threshold for vertical separation can be adjusted if needed |
| 166 | + |
| 167 | +## ?? Known Limitations |
| 168 | + |
| 169 | +1. Very complex schemas with many overlapping relationships may still have visual clutter |
| 170 | +2. The 40% midpoint is a heuristic and may not be optimal for all layouts |
| 171 | +3. Self-referential loops always go left; right-side loops are not yet supported |
| 172 | + |
| 173 | +## ?? Tips for Best Results |
| 174 | + |
| 175 | +- Arrange related tables vertically to leverage angled routing |
| 176 | +- Keep tables with many relationships spread out to reduce line overlap |
| 177 | +- Use the zoom controls to get an overview of complex schemas |
| 178 | +- Click tables to highlight their relationships and reduce visual noise |
0 commit comments