🎁 Get the FREE AI Skills Starter GuideSubscribe →
BytesAgainBytesAgain
🦀 ClawHub

Object Relational Structural Mapping Guide

by @quochungto

Object-relational mapping structural patterns guide. Use when designing or auditing how domain objects map to relational tables — identity fields, foreign ke...

Versionv1.0.0
When to Use
TriggerAction
- Designing how a domain model maps to a relational schema for the first time
- Auditing an existing ORM configuration and schema for structural problems
- Deciding how to map a specific relationship type (1:1, 1:N, N:M, value object, child graph)
- Evaluating whether a JSON/BLOB column is the right choice for nested data
- Debugging N+1 queries, cascade failures, or query-impossible data buried in a LOB
**Not for:**
- Inheritance hierarchies → use `inheritance-mapping-selector`
- Data-source gateway selection (Active Record vs Data Mapper) → use `data-source-pattern-selector`
💡 Examples

Example 1: E-Commerce Order Domain

Trigger: Team is designing the persistence layer for an order management system. Domain classes: Customer, Order, LineItem, Address (value object for shipping and billing).

Process:

  • Customer: entity → Identity Field (surrogate customer_id BIGINT)
  • Order: entity → Identity Field; references Customer → Foreign Key Mapping (order.customer_id FK → customers.customer_id)
  • LineItem: child with no independent identity, only exists within Order → Dependent Mapping (order_id, sequence composite PK or surrogate; cascade all)
  • ShippingAddress / BillingAddress: Value Objects → Embedded Value (columns shipping_street, shipping_city, shipping_zip, billing_street, etc. on the orders table)
  • Order ↔ Promotion (a customer's Order can use multiple Promotions, and a Promotion applies to multiple Orders): N:M → Association Table Mapping (order_promotions(order_id, promotion_id))
  • Output:

    customers(customer_id BIGINT PK, name VARCHAR)
    orders(order_id BIGINT PK, customer_id BIGINT FK, 
           shipping_street VARCHAR, shipping_city VARCHAR, shipping_zip VARCHAR,
           billing_street VARCHAR, billing_city VARCHAR, billing_zip VARCHAR)
    line_items(line_item_id BIGINT PK, order_id BIGINT FK, product_id BIGINT FK, 
               quantity INT, unit_price DECIMAL)
    order_promotions(order_id BIGINT FK, promotion_id BIGINT FK, PRIMARY KEY(order_id, promotion_id))
    

    LineItem uses cascade-delete. ShippingAddress and BillingAddress are Embedded Value — no join needed to load them. Order↔Promotion uses a join table with no attributes (yet).


    Example 2: Music Library with Dependent Tracks

    Trigger: Mapping the Artist/Album/Track domain from PEAA Chapter 12.

    Process:

  • Artist: entity → Identity Field (artist_id BIGINT)
  • Album: entity, references Artist → Identity Field + Foreign Key Mapping (album.artist_id FK → artists.artist_id)
  • Track: child of Album with no identity outside Album context; no other table references Track directly → Dependent Mapping. Album mapper loads/saves/deletes all Tracks. Track has no independent finder.
  • Track has no Identity Field; Album mapper deletes-and-reinserts all Tracks when Album is saved.
  • Output schema:

    artists(artist_id BIGINT PK, name VARCHAR)
    albums(album_id BIGINT PK, artist_id BIGINT FK, title VARCHAR)
    tracks(album_id BIGINT FK, sequence INT, title VARCHAR, duration INT,
           PRIMARY KEY(album_id, sequence))
    

    ORM (Hibernate): @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) on Album → tracks. Tracks loaded when Album is loaded.


    Example 3: Legacy LOB Anti-Pattern Detection

    Trigger: Existing system stores customer contact preferences as XML CLOB in the customers table. Support team needs to query "all customers who prefer email contact." Currently impossible via SQL.

    Process:

  • Identify: customers.preferences_xml CLOB — a Serialized LOB.
  • Apply check: Do SQL queries need to filter on data inside the LOB? Yes — preferred_channel = 'email' must be queryable.
  • Verdict: Anti-pattern. Serialized LOB used for queryable data.
  • Recommendation: Normalize to a customer_preferences table: (customer_id BIGINT FK, preference_key VARCHAR, preference_value VARCHAR) or (customer_id, channel ENUM, enabled BOOLEAN). Apply Foreign Key Mapping.
  • Exception path: If the preference structure is complex and evolving AND a reporting-only database handles the queries, Serialized LOB with JSONB can remain in the operational DB while the reporting DB normalizes the structure.
  • View on ClawHub
    TERMINAL
    clawhub install bookforge-object-relational-structural-mapping-guide

    🧪 Use this skill with your agent

    Most visitors already have an agent. Pick your environment, install or copy the workflow, then run the smoke-test prompt above.

    🔍 Can't find the right skill?

    Search 60,000+ AI agent skills — free, no login needed.

    Search Skills →