annotation Athena::ORM::Annotations::ManyToMany
#
Maps an instance variable to a collection of entities, where each entity may be associated with many entities on the other side. The associations are stored as rows of a join table, holding a foreign key column to each side.
@[AORMA::Entity]
class User < AORM::Entity
# ...
@[AORMA::ManyToMany]
property groups : AORM::Collection(Group) = AORM::ArrayCollection(Group).new
end
The target entity is inferred from the collection's type.
Here the join table is user_group, with a user_id column referencing the id of the user, and a group_id column referencing the id of the group.
Use AORMA::JoinTable, AORMA::JoinColumn, and AORMA::InverseJoinColumn to name them differently.
The collection is loaded the first time it's used. Adding or removing elements inserts or deletes the corresponding join table rows when flushing.
Note
When an entity is removed, its join table rows are deleted along with it, unless a join column of the owning side is declared ON DELETE CASCADE.
That's the case for default join columns, i.e. when AORMA::JoinColumn or AORMA::InverseJoinColumn is missing, and for those given on_delete: "CASCADE".
The database is then expected to delete the rows itself.
Bidirectional#
Mapping the association on the target entity too allows navigating it from both sides. Either side can be the owning side, which writes the join table rows. The inverse side names the owning side's property via mapped_by, and the owning side names the inverse side's property via inversed_by:
@[AORMA::Entity]
class User < AORM::Entity
# The owning side.
@[AORMA::ManyToMany(inversed_by: "users")]
property groups : AORM::Collection(Group) = AORM::ArrayCollection(Group).new
def add_group(group : Group) : Nil
@groups << group
group.users << self
end
end
@[AORMA::Entity]
class Group < AORM::Entity
# The inverse side.
@[AORMA::ManyToMany(mapped_by: "groups")]
property users : AORM::Collection(User) = AORM::ArrayCollection(User).new
end
Only changes to the owning side's collection are written to the join table.
Choose the side that's responsible for managing the association as the owning side, and keep the other side in sync, as add_group does above.
Configuration#
Optional Arguments#
mapped_by#
Type: String? Default: nil
The name of the owning side's property on the target entity. Makes this property the inverse side of the association.
inversed_by#
Type: String? Default: nil
The name of the inverse side's property on the target entity, if the association is bidirectional.
cascade#
Type: Array(String)? Default: nil
The operations on this entity that are also applied to the entities in the collection, see the associations section of the manual.
One or more of "persist", "remove", "detach", or "all".
orphan_removal#
Type: Bool Default: false
Whether entities removed from the collection are removed from the database.
target_entity#
Type: AORM::Entity.class? Default: the collection's type argument
The class of the associated entities, if it can't be inferred from the instance variable's type.
fetch_mode#
Type: AORM::Mapping::FetchMode Default: :lazy
When the collection is loaded.
Todo
Not supported yet; it's ignored, and collections are always loaded lazily.
index_by#
Type: String? Default: nil
The field of the target entity the collection is indexed by.
Todo
Not supported yet; it's ignored.