Associations topic

Associations define relationships between models, enabling you to work with related data efficiently via eager loading and foreign key management.

Association Types

Annotation Relationship Example
@HasOne One-to-one User has one Profile
@HasMany One-to-many User has many Posts
@BelongsTo Child-parent Post belongs to User

Defining Associations

@Table(tableName: 'users', underscored: true)
class Users {
  @PrimaryKey()
  @AutoIncrement()
  DataType id = DataType.INTEGER;

  DataType email = DataType.STRING;

  @HasMany(Post, foreignKey: 'user_id', as_: 'posts')
  DataType posts = DataType.INTEGER;

  @HasOne(Profile, foreignKey: 'user_id', as_: 'profile')
  DataType profile = DataType.INTEGER;

  static UsersModel get model => UsersModel();
}

@Table(tableName: 'posts', underscored: true)
class Post {
  @PrimaryKey()
  @AutoIncrement()
  DataType id = DataType.INTEGER;

  DataType title = DataType.STRING;
  DataType content = DataType.TEXT;

  @BelongsTo(Users, foreignKey: 'user_id', as_: 'user')
  DataType user = DataType.INTEGER;

  static PostModel get model => PostModel();
}

Eager Loading

Fetch related data in a single query using the type-safe include option.

// Load users with their posts
final users = await Users.model.findAll(
  include: (u) => [u.posts()],
);

// Load user with profile and posts (nested)
final user = await Users.model.findOne(
  where: (u) => u.id.eq(1),
  include: (u) => [
    u.profile(),
    u.posts(
      where: (p) => p.title.like('%Dart%'),
      limit: 5,
    ),
  ],
);

Inner Join (Required)

By default, Sequelize uses a LEFT OUTER JOIN. Set required: true for an INNER JOIN — only returns records that have the association.

final usersWithPosts = await Users.model.findAll(
  include: (u) => [
    u.posts(required: true),
  ],
);

Nested Eager Loading

Load associations of associations to any depth.

final users = await Users.model.findAll(
  include: (u) => [
    u.posts(
      include: (p) => [
        p.comments(),  // Load comments for each post
      ],
    ),
  ],
);

Separate Queries

For @HasMany associations, use separate: true to run a separate query instead of a JOIN. This avoids Cartesian product issues with multiple one-to-many includes.

final users = await Users.model.findAll(
  include: (u) => [
    u.posts(separate: true, limit: 10),
  ],
);

BelongsTo Mixin Methods

Generated BelongsTo associations include helper methods:

// Get the associated parent
final user = await post.getUser();

// Set a new parent
await post.setUser(anotherUser);

// Create a new parent
final newUser = await post.createUser(
  CreateUsers(email: 'new@example.com', firstName: 'New'),
);

Classes

AssociationReference<T> Associations
Type-safe reference to a model association.
BelongsTo Associations
Defines an association where the foreign key exists on the source (this) model, pointing to the target model's primary key.
HasMany Associations
Defines a one-to-many association where the foreign key exists on the target model.
HasOne Associations
Defines a one-to-one association where the foreign key exists on the target model.
IncludeBuilder<T> Associations
Builder for creating type-safe include configurations.
IncludeHelper Associations
Base class for include helpers.