Class ToMany<TARGET>

java.lang.Object
io.objectbox.relation.ToMany<TARGET>
Type Parameters:
TARGET - target object type (@Entity class).
All Implemented Interfaces:
Serializable, Iterable<TARGET>, Collection<TARGET>, List<TARGET>, SequencedCollection<TARGET>

public class ToMany<TARGET> extends Object implements List<TARGET>, Serializable
A to-many relation of an entity that references multiple objects of a ToMany entity.

Example:


 // Java
 @Entity
 public class Student{
     private ToMany<Teacher> teachers;
 }

 // Kotlin
 @Entity
 data class Student() {
     lateinit var teachers: ToMany<Teacher>
 }
 

Implements the List interface and uses lazy initialization. The target objects are only read from the database when the list is first accessed.

The required database query runs on the calling thread, so avoid accessing ToMany from a UI or main thread. To get the latest data Box.get(long) the object with the ToMany again or use reset() before accessing the list again. It is possible to preload the list when running a query using QueryBuilder.eager(io.objectbox.relation.RelationInfo, io.objectbox.relation.RelationInfo...).

Tracks when target objects are added and removed. Common usage:

To apply (persist) the changes to the database, call applyChangesToDb() or put the object with the ToMany. For important details, see the notes about relations of Box.put(Object).


 // Example 1: add target objects to a relation
 student.getTeachers().add(teacher1);
 student.getTeachers().add(teacher2);
 store.boxFor(Student.class).put(student);

 // Example 2: remove a target object from the relation
 student.getTeachers().remove(index);
 student.getTeachers().applyChangesToDb();
 // or store.boxFor(Student.class).put(student);
 

In the database, the target objects are referenced by their IDs, which are persisted as part of the relation of the object with the ToMany.

ToMany is thread-safe by default (may not be the case if setListFactory(ListFactory) is used).

To get all objects with a ToMany that reference a target object, see Backlink.

See Also:
  • Field Details

    • serialVersionUID

      private static final long serialVersionUID
      See Also:
    • ONE

      private static final Integer ONE
    • entity

      private final Object entity
    • relationInfo

      private final RelationInfo<Object,TARGET> relationInfo
    • listFactory

      private volatile ListFactory listFactory
    • entities

      private List<TARGET> entities
    • entityCounts

      private Map<TARGET,Integer> entityCounts
      Counts of all entities in the list (entities).
    • entitiesAdded

      private volatile Map<TARGET,Boolean> entitiesAdded
      Entities added since last put/sync. Map is used as a set (value is always Boolean.TRUE).
    • entitiesRemoved

      private Map<TARGET,Boolean> entitiesRemoved
      Entities removed since last put/sync. Map is used as a set (value is always Boolean.TRUE).
    • entitiesToPut

      List<TARGET> entitiesToPut
    • entitiesToRemoveFromDb

      List<TARGET> entitiesToRemoveFromDb
    • boxStore

      private transient BoxStore boxStore
    • entityBox

      private transient Box<Object> entityBox
    • targetBox

      private transient volatile Box<TARGET> targetBox
    • removeFromTargetBox

      private transient boolean removeFromTargetBox
    • comparator

      private transient Comparator<TARGET> comparator
  • Constructor Details

  • Method Details

    • setListFactory

      @Experimental public void setListFactory(ListFactory listFactory)
      Currently only used for non-persisted entities (id == 0).
    • setComparator

      @Experimental public void setComparator(Comparator<TARGET> comparator)
      Set an comparator to define the order of entities.
    • setRemoveFromTargetBox

      @Experimental public void setRemoveFromTargetBox(boolean removeFromTargetBox)
      On put, this also deletes removed entities from the target Box. Note: removed target entities won't cascade the delete.
    • getListFactory

      public ListFactory getListFactory()
    • ensureBoxes

      private void ensureBoxes()
    • ensureEntitiesWithTrackingLists

      private void ensureEntitiesWithTrackingLists()
    • ensureEntities

      private void ensureEntities()
    • add

      public boolean add(TARGET object)
      Prepares to add the given target object to this relation.

      To apply changes, call applyChangesToDb() or put the object with the ToMany. For important details, see the notes about relations of Box.put(Object).

      Specified by:
      add in interface Collection<TARGET>
      Specified by:
      add in interface List<TARGET>
    • trackAdd

      private void trackAdd(TARGET object)
      Must be called from a synchronized method
    • trackAdd

      private void trackAdd(Collection<? extends TARGET> objects)
      Must be called from a synchronized method
    • trackRemove

      private void trackRemove(TARGET object)
      Must be called from a synchronized method
    • add

      public void add(int location, TARGET object)
      See add(Object) for general comments.
      Specified by:
      add in interface List<TARGET>
    • addAll

      public boolean addAll(Collection<? extends TARGET> objects)
      See add(Object) for general comments.
      Specified by:
      addAll in interface Collection<TARGET>
      Specified by:
      addAll in interface List<TARGET>
    • addAll

      public boolean addAll(int index, Collection<? extends TARGET> objects)
      See add(Object) for general comments.
      Specified by:
      addAll in interface List<TARGET>
    • clear

      public void clear()
      Specified by:
      clear in interface Collection<TARGET>
      Specified by:
      clear in interface List<TARGET>
    • contains

      public boolean contains(Object object)
      Specified by:
      contains in interface Collection<TARGET>
      Specified by:
      contains in interface List<TARGET>
    • containsAll

      public boolean containsAll(Collection<?> collection)
      Specified by:
      containsAll in interface Collection<TARGET>
      Specified by:
      containsAll in interface List<TARGET>
    • get

      public TARGET get(int location)
      Gets the target object at the given index.

      ToMany uses lazy initialization, so on first access this will read the target objects from the database.

      Specified by:
      get in interface List<TARGET>
    • indexOf

      public int indexOf(Object object)
      Specified by:
      indexOf in interface List<TARGET>
    • isEmpty

      public boolean isEmpty()
      Specified by:
      isEmpty in interface Collection<TARGET>
      Specified by:
      isEmpty in interface List<TARGET>
    • iterator

      @Nonnull public Iterator<TARGET> iterator()
      Specified by:
      iterator in interface Collection<TARGET>
      Specified by:
      iterator in interface Iterable<TARGET>
      Specified by:
      iterator in interface List<TARGET>
    • lastIndexOf

      public int lastIndexOf(Object object)
      Specified by:
      lastIndexOf in interface List<TARGET>
    • listIterator

      @Nonnull public ListIterator<TARGET> listIterator()
      Specified by:
      listIterator in interface List<TARGET>
    • listIterator

      @Nonnull public ListIterator<TARGET> listIterator(int location)
      The returned iterator does not track any potential calls to Iterator.remove(). Thus these removes will NOT be synced to the target Box.
      Specified by:
      listIterator in interface List<TARGET>
    • remove

      public TARGET remove(int location)
      Like remove(Object), but using the location of the target object.
      Specified by:
      remove in interface List<TARGET>
    • remove

      public boolean remove(Object object)
      Prepares to remove the target object from this relation.

      To apply changes, call applyChangesToDb() or put the object with the ToMany. For important details, see the notes about relations of Box.put(Object).

      Specified by:
      remove in interface Collection<TARGET>
      Specified by:
      remove in interface List<TARGET>
    • removeById

      public TARGET removeById(long id)
      Like remove(Object), but using just the ID of the target object.
    • removeAll

      public boolean removeAll(Collection<?> objects)
      Specified by:
      removeAll in interface Collection<TARGET>
      Specified by:
      removeAll in interface List<TARGET>
    • retainAll

      public boolean retainAll(Collection<?> objects)
      Specified by:
      retainAll in interface Collection<TARGET>
      Specified by:
      retainAll in interface List<TARGET>
    • set

      public TARGET set(int location, TARGET object)
      Specified by:
      set in interface List<TARGET>
    • size

      public int size()
      Specified by:
      size in interface Collection<TARGET>
      Specified by:
      size in interface List<TARGET>
    • subList

      @Nonnull public List<TARGET> subList(int start, int end)
      The returned sub list does not do any change tracking. Thus any modifications to the sublist won't be synced to the target Box.
      Specified by:
      subList in interface List<TARGET>
    • toArray

      @Nonnull public Object[] toArray()
      Specified by:
      toArray in interface Collection<TARGET>
      Specified by:
      toArray in interface List<TARGET>
    • toArray

      @Nonnull public <T> T[] toArray(T[] array)
      Specified by:
      toArray in interface Collection<TARGET>
      Specified by:
      toArray in interface List<TARGET>
    • reset

      public void reset()
      Resets the already loaded (cached) objects of this list, so they will be re-loaded when accessing this list again.

      Use this to sync with changes to this relation or target objects made outside of this ToMany.

    • isResolved

      public boolean isResolved()
    • getAddCount

      public int getAddCount()
    • getRemoveCount

      public int getRemoveCount()
    • sortById

      public void sortById()
      Sorts the list by the "natural" ObjectBox order for to-many list (by object ID). This will be the order when you get the objects fresh (e.g. initially or after calling reset()). Note that non persisted objects (ID is zero) will be put to the end as they are still to get an ID.
    • applyChangesToDb

      public void applyChangesToDb()
      Saves changes (added and removed objects) made to this relation to the database. For some important details, see the notes about relations of Box.put(Object).

      Note that this is called already when the object that contains this ToMany is put. However, if only this ToMany has changed, it is more efficient to just use this method.

      Throws:
      IllegalStateException - If the object that contains this ToMany has no ID assigned (it must have been put before).
    • hasA

      @Beta public boolean hasA(QueryFilter<TARGET> filter)
      Returns true if at least one of the target objects matches the given filter.

      For use with QueryBuilder.filter(QueryFilter) inside a QueryFilter to check to-many relation objects.

    • hasAll

      @Beta public boolean hasAll(QueryFilter<TARGET> filter)
      Returns true if all of the target objects match the given filter. Returns false if the list is empty.

      For use with QueryBuilder.filter(QueryFilter) inside a QueryFilter to check to-many relation objects.

    • getById

      @Beta public TARGET getById(long id)
      Gets an object by its ID.
    • indexOfId

      @Beta public int indexOfId(long id)
      Gets the index of the object with the given ID.
    • hasPendingDbChanges

      public boolean hasPendingDbChanges()
      Returns true if there are pending changes for the DB. Changes will be automatically persisted once the object with the ToMany is put, or an explicit call to applyChangesToDb() is made.
    • internalCheckApplyToDbRequired

      @Internal public boolean internalCheckApplyToDbRequired()
      For internal use only; do not use in your app. Called after relation source object is put (so we have its ID). Prepares data for internalApplyToDb(Cursor, Cursor)
    • prepareToManyBacklinkEntitiesForDb

      private boolean prepareToManyBacklinkEntitiesForDb(long entityId, IdGetter<TARGET> idGetter, @Nullable Map<TARGET,Boolean> setAdded, @Nullable Map<TARGET,Boolean> setRemoved)
      Modifies the linked ToMany relation of added or removed target objects and schedules put by internalApplyToDb(io.objectbox.Cursor<?>, io.objectbox.Cursor<TARGET>) for them.

      If setRemoveFromTargetBox(boolean) is true, removed target objects are scheduled for removal instead of just updating their ToMany relation.

      If target objects are new, schedules a put if they were added, but never if they were removed from this relation.

      Returns:
      Whether there are any target objects to put or remove.
    • prepareToOneBacklinkEntitiesForDb

      private boolean prepareToOneBacklinkEntitiesForDb(long entityId, IdGetter<TARGET> idGetter, @Nullable Map<TARGET,Boolean> setAdded, @Nullable Map<TARGET,Boolean> setRemoved)
    • internalApplyToDb

      @Internal public void internalApplyToDb(Cursor<?> sourceCursor, Cursor<TARGET> targetCursor)
      For internal use only; do not use in your app. Convention: internalCheckApplyToDbRequired() must be called before this call as it prepares .
    • removeStandaloneRelations

      private void removeStandaloneRelations(Cursor<?> cursor, long sourceEntityId, List<TARGET> removed, IdGetter<TARGET> targetIdGetter)
      The list of removed entities may contain non-persisted entities, which will be ignored (removed from the list).
    • addStandaloneRelations

      private void addStandaloneRelations(Cursor<?> cursor, long sourceEntityId, TARGET[] added, IdGetter<TARGET> targetIdGetter)
      The target array may not contain non-persisted entities.
    • getEntity

      Object getEntity()
      For tests