Skip to content

module Athena::ORM::Collection(T) #

The type of an entity's AORMA::OneToMany and AORMA::ManyToMany association fields.

Type the property as AORM::Collection(T), where T is the associated entity, and initialize it with an empty AORM::ArrayCollection(T):

@[AORMA::Entity]
class User < AORM::Entity
  # ...

  @[AORMA::ManyToMany(inversed_by: "users")]
  property groups : AORM::Collection(Group) = AORM::ArrayCollection(Group).new

  # Keeps both sides of the association in sync in memory.
  def add_group(group : Group) : Nil
    self.groups << group
    group.users << self
  end
end

user = User.new
user.add_group Group.new # Works before the user is ever persisted

Warning

The default value is required, since the ORM reads the element type from it.

The ORM swaps the collection for an AORM::PersistentCollection(T):

  • When a flush processes the entity, any other collection assigned to the field is replaced by a persistent one holding the same elements.
  • When the entity is loaded from the database, the field holds a persistent collection whose elements aren't loaded yet. They're loaded with a single query the first time the collection is read, see AORM::PersistentCollection.

So code should only rely on the AORM::Collection(T) API, not on the field holding a specific implementation. Both implementations are Indexable(T), so the usual Enumerable and Indexable methods are available alongside <<, delete, remove_element, includes? and clear.

Owning and inverse sides#

Only changes to the owning side of an association are written to the database. Adding an element to, or removing one from, a AORMA::ManyToMany collection without mapped_by inserts or deletes its row in the join table on the next flush. A AORMA::OneToMany collection is always the inverse side: the foreign key lives on the element's AORMA::ManyToOne field, so set that field for the change to be written. Changes made only to an inverse side are ignored, so keep both sides in sync, as add_group does above.

New entities added to a collection are only inserted if they're persisted themselves, or the association is mapped with cascade: ["persist"]; otherwise the flush raises. Once a flush deletes an entity, it's also removed from the loaded collections of managed entities that still contained it.

Direct including types

Athena::ORM::AbstractLazyCollection(T) Athena::ORM::ArrayCollection(T)