Many To Many

CQL Active Record: ManyToMany Relationship Guide

In this guide, we'll cover the ManyToMany relationship using CQL's Active Record syntax. This relationship is used when multiple records in one table can relate to multiple records in another table, facilitated by an intermediate join table.


What is a ManyToMany Relationship?

A ManyToMany relationship means that multiple records in one table can relate to multiple records in another table. For example:

  • A Post can have multiple Tags (e.g., "Tech", "News").

  • A Tag can belong to multiple Posts (e.g., both Post 1 and Post 2 can have the "Tech" tag).

Example Scenario: Posts and Tags

We'll use a scenario where:

  • A Post can have many Tags.

  • A Tag can belong to many Posts.

We will represent this many-to-many relationship using a join table called PostTags.


Defining the Schema

We'll define the posts, tags, and post_tags tables in the schema using CQL's DSL.

  • posts table: Stores post details such as title, body, and published_at.

  • tags table: Stores tag names.

  • post_tags table: A join table that connects posts and tags via their foreign keys post_id and tag_id.


Defining the Models

Let's define the Post, Tag, and PostTag models in CQL, establishing the ManyToMany relationship.

Post Model

  • The many_to_many :tags, Tag, join_through: :post_tags association in the Post model connects Post to Tag via the post_tags table.

Tag Model

  • Similarly, the Tag model uses many_to_many :posts, Post, join_through: :post_tags.

PostTag Model (Join Model)

  • The PostTag model is crucial. It belongs_to both Post and Tag.

  • The many_to_many macro uses this join model implicitly via the join_through: :post_tags option, which refers to the table name.


Working with ManyToMany Associations

When you access a many_to_many association (e.g., post.tags), you get a ManyCollection proxy that offers powerful methods to manage the relationship.

Creating and Associating Records

Accessing Associated Records

Removing Associations / Deleting Records

Removing an association (deletes the join table record, not the Tag itself):

Clearing all associations for a post (deletes all its PostTag records):

  • clear only removes the join records. The Tag records themselves are not deleted.

  • If cascade: true was set on the many_to_many association, the behavior of delete or clear with respect to the target records (Tag) might change, potentially deleting them. This needs careful checking of ManyCollection's cascade implementation.

Deleting a Post or a Tag will not automatically delete its associations from the post_tags table or the associated records on the other side, unless cascade deletes are configured at the database level or handled by before_destroy callbacks manually cleaning up join table records.


Efficient Querying for ManyToMany

To avoid N+1 queries with many-to-many associations, use join:


Summary

In this guide, we explored the ManyToMany relationship in CQL:

  • Defined Post, Tag, and PostTag (join) models using CQL::ActiveRecord::Model(Pk).

  • Used the many_to_many :association, TargetModel, join_through: :join_table_symbol macro.

  • Showcased managing associations using ManyCollection methods like <<, create, delete, and clear.

  • Discussed accessing associated records and eager loading with includes.

This provides a robust way to handle many-to-many relationships in your Crystal applications using CQL.

Next Steps

This concludes our series of guides on relationships in CQL Active Record, covering BelongsTo, HasOne, HasMany, and ManyToMany. Feel free to experiment by extending your models, adding validations, or implementing more complex queries to suit your needs.

Last updated

Was this helpful?