Relationships
ReActive Record provides several types of relationships to define connections between your models. These relationships are reactive, meaning changes to related models will automatically update across your application.
Types of Relationships
One-to-One Relationships
- HasOne: A model has exactly one instance of another model
- BelongsTo: The inverse of HasOne, where a model belongs to another model
One-to-Many Relationships
- HasMany: A model has multiple instances of another model
- HasManyThrough: A model has multiple instances of another model through an intermediate model
Many-to-Many Relationships
- ManyToMany: Models that can have multiple instances of each other
Polymorphic Relationships
- MorphMany: A model has multiple instances of multiple possible model types
- MorphOne: A model has one instance of multiple possible model types
- MorphTo: The inverse of MorphOne/MorphMany
Common Features
Relationship Loading
Relationships are lazy-loaded by default. You can load them in several ways:
Manual Loading
typescript
// Load a single relationship
const user = await User.find(1)
await user.load('profile')
// Load multiple relationships
await user.loadMany(['profile', 'posts'])
Eager Loading with Query Builder
typescript
// Load all users with their profiles
const users = await User.query()
.with('profile')
.fetch()
// Load multiple relationships
const users = await User.query()
.with('profile', 'posts')
.fetch()
// Load all defined relationships
const users = await User.query()
.withAll()
.fetch()
Reactivity
All relationships in ReActive Record are reactive, meaning:
- Changes to related models are automatically reflected
- You can listen to changes on related models
- Changes are propagated across the application
Example of reactive relationships:
typescript
const user = await User.find(1)
await user.load('profile')
// Listen to changes on the profile
user.onPropertyChange('profile', (newProfile, oldProfile) => {
console.log('Profile changed:', { new: newProfile, old: oldProfile })
})
// Listen to specific property changes on the profile
user.profile.onPropertyChange('full_name', (newName, oldName) => {
console.log('Name changed:', { new: newName, old: oldName })
})
Important Notes
- Relationships are lazy-loaded by default
- Use eager loading (
with()
) when you know you'll need related models - Relationship changes are reactive and will update automatically
- Changes to related models trigger appropriate events on the parent model
- You can chain relationship loading with other query builder methods
See the individual relationship documentation for specific details about each type of relationship.