Relation Types Overview
Sonamu supports 4 Relation types:BelongsToOne
N:1 relationship - Many reference one Example: Post → User (multiple posts belong to one user)
OneToOne
1:1 relationship - One references one Example: User ↔ Employee (user and employee info are 1:1
matched)
HasMany
1:N relationship - One owns many Example: User → Posts (one user owns multiple posts)
ManyToMany
N:M relationship - Many-to-many Example: Post ↔ Tag (many-to-many between posts and tags)
BelongsToOne
N:1 relationship - The current Entity belongs to another Entity.Basic Usage
post.entity.json
user_id (integer, not null)
Database structure:
Options
| Option | Type | Description | Default |
|---|---|---|---|
nullable | boolean | Allow NULL | false |
useConstraint | boolean | Use Foreign Key constraint | true |
onUpdate | RelationOn | Action on referenced record update | RESTRICT |
onDelete | RelationOn | Action on referenced record delete | RESTRICT |
customJoinClause | string | Custom JOIN condition | - |
RelationOn Options
| Value | Description | Use Case |
|---|---|---|
CASCADE | Change/delete child when parent changes | Delete posts when user is deleted |
SET NULL | Set child’s FK to NULL when parent deleted | Set employee’s department to NULL when department deleted |
RESTRICT | Prevent parent change/delete if children exist | Cannot delete user if posts exist |
NO ACTION | Similar to RESTRICT, different check timing | - |
SET DEFAULT | Set to default value when parent deleted | - |
Example: nullable and CASCADE
department_idallowsNULL- When department is deleted, employee’s
department_idis set toNULL
TypeScript Usage
OneToOne
1:1 relationship - Two Entities reference each other exactly once.Basic Usage
OneToOne can be defined in two ways:- hasJoinColumn: true
- hasJoinColumn: false
FK column is created in the current Entity.Generated column:
employee.entity.json
user_id (integer, unique, not null)Database structure:Options
| Option | Type | Description | Default |
|---|---|---|---|
hasJoinColumn | boolean | Whether to create FK column | required |
nullable | boolean | Allow NULL (when hasJoinColumn: true) | false |
useConstraint | boolean | FK constraint (when hasJoinColumn: true) | true |
onUpdate | RelationOn | Action on update (when hasJoinColumn: true) | RESTRICT |
onDelete | RelationOn | Action on delete (when hasJoinColumn: true) | RESTRICT |
customJoinClause | string | Custom JOIN condition | - |
Example: Bidirectional OneToOne
- User can optionally have an Employee (nullable)
- Employee must have a User (not null)
- When User is deleted, Employee is also deleted (CASCADE)
HasMany
1:N relationship - One Entity owns multiple other Entities.Basic Usage
user.entity.json
PostEntity must have auser_idcolumn- Usually defined with
BelongsToOnein reverse onPost
Options
| Option | Type | Description | Default |
|---|---|---|---|
joinColumn | string | FK column name in the other table | required |
fromColumn | string | Reference column name in current table | id |
nullable | boolean | Nullable for the relation itself (optional) | false |
Example: Using fromColumn
TypeScript Usage
HasMany is automatically optimized using the DataLoader pattern. N+1 query problems don’t
occur.
ManyToMany
N:M relationship - Many-to-many relationship implemented through a join table.Basic Usage
post.entity.json
Options
| Option | Type | Description | Default |
|---|---|---|---|
joinTable | string | Join table name ({table1}__${table2}) | required |
onUpdate | RelationOn | Action on referenced record update | required |
onDelete | RelationOn | Action on referenced record delete | required |
nullable | boolean | Nullable for the relation itself (optional) | false |
Bidirectional Definition
TypeScript Usage
Custom Join Clause
You can write SQL expressions directly when complex JOIN conditions are needed.Relation Usage Patterns
1. Selecting Relation Fields in Subsets
user: LEFT JOINtags: Separate query via DataLoader
2. Nested Relations
3. Filtering Relations
4. Sorting by Relations
Relation Design Guide
BelongsToOne vs OneToOne
| Situation | Recommended Type | Reason |
|---|---|---|
| Post → Author | BelongsToOne | Multiple posts belong to one user |
| User ↔ Profile | OneToOne | 1:1 matching relationship |
| Order → Customer | BelongsToOne | Multiple orders belong to one customer |
CASCADE vs RESTRICT
| Situation | Recommended Action | Reason |
|---|---|---|
| User delete → Posts | CASCADE | Delete together |
| Category delete → Posts | RESTRICT | Cannot delete if posts exist |
| Department delete → Employees | SET NULL | Keep employees, set department to NULL |
nullable Setting
| Situation | nullable | Reason |
|---|---|---|
| Required relationship | false | Reference always needed |
| Optional relationship | true | May not exist |
| Temporary state | true | Set later |
Cautions
Next Steps
Enums
Define and use Enum types
Subset
Type-safe queries with Subsets
Puri Query Builder
Write queries using Relations
Performance
Optimize Relation queries