35
35
import io .objectbox .BoxStore ;
36
36
import io .objectbox .Cursor ;
37
37
import io .objectbox .InternalAccess ;
38
+ import io .objectbox .annotation .Backlink ;
38
39
import io .objectbox .annotation .apihint .Beta ;
39
40
import io .objectbox .annotation .apihint .Experimental ;
40
41
import io .objectbox .annotation .apihint .Internal ;
43
44
import io .objectbox .internal .ReflectionCache ;
44
45
import io .objectbox .internal .ToManyGetter ;
45
46
import io .objectbox .internal .ToOneGetter ;
47
+ import io .objectbox .query .QueryBuilder ;
46
48
import io .objectbox .query .QueryFilter ;
47
49
import io .objectbox .relation .ListFactory .CopyOnWriteArrayListFactory ;
48
50
49
51
import static java .lang .Boolean .TRUE ;
50
52
51
53
/**
52
- * A List representing a to-many relation.
53
- * It tracks changes (adds and removes) that can be later applied (persisted) to the database.
54
- * This happens either on {@link Box#put(Object)} of the source entity of this relation or using
55
- * {@link #applyChangesToDb()}.
54
+ * A lazily loaded {@link List} of target objects representing a to-many relation, a unidirectional link from a "source"
55
+ * entity to multiple objects of a "target" entity.
56
56
* <p>
57
- * If this relation is a backlink from a {@link ToOne} relation, a DB sync will also update ToOne objects
58
- * (but not vice versa).
57
+ * It tracks changes (adds and removes) that can be later applied (persisted) to the database. This happens either when
58
+ * the object that contains this relation is put or using {@link #applyChangesToDb()}. For some important details about
59
+ * applying changes, see the notes about relations of {@link Box#put(Object)}.
59
60
* <p>
60
- * ToMany is thread-safe by default (only if the default {@link java.util.concurrent.CopyOnWriteArrayList} is used).
61
+ * The objects are loaded lazily on first access of this list, and then cached. The database query runs on the calling
62
+ * thread, so avoid accessing this from a UI or main thread. Subsequent calls to any method, like {@link #size()}, do
63
+ * not query the database, even if the relation was changed elsewhere. To get the latest data {@link Box#get} the source
64
+ * object again or use {@link #reset()} before accessing the list again.
65
+ * <p>
66
+ * It is possible to preload the list when running a query using {@link QueryBuilder#eager}.
67
+ * <p>
68
+ * ToMany is thread-safe by default (may not be the case if {@link #setListFactory(ListFactory)} is used).
61
69
*
62
70
* @param <TARGET> Object type (entity).
63
71
*/
@@ -482,8 +490,10 @@ public <T> T[] toArray(T[] array) {
482
490
}
483
491
484
492
/**
485
- * Resets the already loaded entities so they will be re-loaded on their next access.
486
- * This allows to sync with non-tracked changes (outside of this ToMany object).
493
+ * Resets the already loaded (cached) objects of this list, so they will be re-loaded when accessing this list
494
+ * again.
495
+ * <p>
496
+ * Use this to sync with changes to this relation or target objects made outside of this ToMany.
487
497
*/
488
498
public synchronized void reset () {
489
499
entities = null ;
@@ -540,12 +550,14 @@ else if (delta > 0)
540
550
}
541
551
542
552
/**
543
- * Applies (persists) tracked changes (added and removed entities) to the target box
544
- * and/or updates standalone relations.
545
- * Note that this is done automatically when you put the source entity of this to-many relation.
546
- * However, if only this to-many relation has changed, it is more efficient to call this method.
553
+ * Saves changes (added and removed entities) made to this relation to the database. For some important details, see
554
+ * the notes about relations of {@link Box#put(Object)}.
555
+ * <p>
556
+ * Note that this is called already when the object that contains this ToMany is put. However, if only this ToMany
557
+ * has changed, it is more efficient to just use this method.
547
558
*
548
- * @throws IllegalStateException If the source entity of this to-many relation was not previously persisted
559
+ * @throws IllegalStateException If the object that contains this ToMany has no ID assigned (it must have been put
560
+ * before).
549
561
*/
550
562
public void applyChangesToDb () {
551
563
long id = relationInfo .sourceInfo .getIdGetter ().getId (entity );
@@ -571,7 +583,7 @@ public void applyChangesToDb() {
571
583
/**
572
584
* Returns true if at least one of the entities matches the given filter.
573
585
* <p>
574
- * For use with {@link io.objectbox.query. QueryBuilder#filter(QueryFilter)} inside a {@link QueryFilter} to check
586
+ * For use with {@link QueryBuilder#filter(QueryFilter)} inside a {@link QueryFilter} to check
575
587
* to-many relation entities.
576
588
*/
577
589
@ Beta
@@ -589,7 +601,7 @@ public boolean hasA(QueryFilter<TARGET> filter) {
589
601
/**
590
602
* Returns true if all of the entities match the given filter. Returns false if the list is empty.
591
603
* <p>
592
- * For use with {@link io.objectbox.query. QueryBuilder#filter(QueryFilter)} inside a {@link QueryFilter} to check
604
+ * For use with {@link QueryBuilder#filter(QueryFilter)} inside a {@link QueryFilter} to check
593
605
* to-many relation entities.
594
606
*/
595
607
@ Beta
@@ -694,6 +706,17 @@ public boolean internalCheckApplyToDbRequired() {
694
706
}
695
707
}
696
708
709
+ /**
710
+ * Modifies the {@link Backlink linked} ToMany relation of added or removed target objects and schedules put by
711
+ * {@link #internalApplyToDb} for them.
712
+ * <p>
713
+ * If {@link #setRemoveFromTargetBox} is true, removed target objects are scheduled for removal instead of just
714
+ * updating their ToMany relation.
715
+ * <p>
716
+ * If target objects are new, schedules a put if they were added, but never if they were removed from this relation.
717
+ *
718
+ * @return Whether there are any target objects to put or remove.
719
+ */
697
720
private boolean prepareToManyBacklinkEntitiesForDb (long entityId , IdGetter <TARGET > idGetter ,
698
721
@ Nullable Map <TARGET , Boolean > setAdded , @ Nullable Map <TARGET , Boolean > setRemoved ) {
699
722
ToManyGetter <TARGET , Object > backlinkToManyGetter = relationInfo .backlinkToManyGetter ;
@@ -738,6 +761,9 @@ private boolean prepareToManyBacklinkEntitiesForDb(long entityId, IdGetter<TARGE
738
761
}
739
762
}
740
763
764
+ /**
765
+ * Like {@link #prepareToManyBacklinkEntitiesForDb} but for the linked ToOne relation.
766
+ */
741
767
private boolean prepareToOneBacklinkEntitiesForDb (long entityId , IdGetter <TARGET > idGetter ,
742
768
@ Nullable Map <TARGET , Boolean > setAdded , @ Nullable Map <TARGET , Boolean > setRemoved ) {
743
769
ToOneGetter <TARGET , Object > backlinkToOneGetter = relationInfo .backlinkToOneGetter ;
0 commit comments