Skip to content

Commit

Permalink
Merge branch 'relation-docs-updates' into 'main'
Browse files Browse the repository at this point in the history
Relation docs updates

See merge request objectbox/objectbox-dart!87
  • Loading branch information
greenrobot-team committed Jun 10, 2024
2 parents ad5a9ab + 772c1f1 commit 2bb12c3
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 65 deletions.
72 changes: 39 additions & 33 deletions objectbox/lib/src/relations/to_many.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,43 @@ import '../store.dart';
import '../transaction.dart';
import 'info.dart';

/// A lazily loaded `List` of target objects representing a to-many relation,
/// a unidirectional link from a "source" entity to multiple objects of a
/// "target" entity.
///
/// It tracks changes (adds and removes) that can be later applied (persisted)
/// to the database. This happens either when the source entity of this relation
/// is put or using [applyToDb]. For some important details about applying
/// changes, see the notes about relations of [Box.put].
///
/// The objects are loaded lazily on first access of this list, and then cached.
/// Subsequent calls to any method, like [length], do not query the database,
/// even if the relation was changed elsewhere. To get the latest data [Box.get]
/// the source object again.
///
/// You can:
/// - [add] new objects to the relation.
/// - [removeAt] target objects from the relation at a specific list index.
/// - [remove] target objects from the relation by an ID.
/// A to-many relation of an entity that references multiple objects of a "target" entity [EntityT].
///
/// Example:
/// ```
/// @Entity()
/// class Student {
/// final teachers = ToMany<Teacher>();
/// }
/// ```
///
/// // Example 1: create a relation
/// final teacher1 = Teacher();
/// final teacher2 = Teacher();
/// Implements the `List` interface and uses lazy initialization.
/// The target objects are only read from the database when the list is first accessed.
///
/// final student1 = Student();
/// student1.teachers.add(teacher1);
/// student1.teachers.add(teacher2);
/// Tracks when target objects are added and removed. Common usage:
/// - [add] target objects to the relation.
/// - [remove] target objects from the relation.
/// - [removeAt] target objects at a specific index.
///
/// final student2 = Student();
/// student2.teachers.add(teacher2);
/// To apply (persist) the changes to the database, call [applyToDb] or put the object with the ToMany.
/// For important details, see the notes about relations of [Box.put].
///
/// // saves students as well as teachers in the database
/// store.box<Student>().putMany([student1, student2]);
/// ```
/// // Example 1: add target objects to a relation
/// student.teachers.add(teacher1);
/// student.teachers.add(teacher2);
/// store.box<Student>().put(student);
///
/// // Example 2: remove a relation
/// student.teachers.removeAt(index)
/// student.teachers.applyToDb(); // or store.box<Student>().put(student);
/// // Example 2: remove a target object from the relation
/// student.teachers.removeAt(index);
/// student.teachers.applyToDb();
/// // or store.box<Student>().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.
///
/// To get all objects with a ToMany that reference a target object, see [Backlink].
class ToMany<EntityT> extends Object with ListMixin<EntityT> {
/// Store-related configuration attached to this.
///
Expand Down Expand Up @@ -92,6 +87,9 @@ class ToMany<EntityT> extends Object with ListMixin<EntityT> {
_items.length = newLength;
}

/// 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.
@override
EntityT operator [](int index) => _items[index];

Expand All @@ -109,6 +107,10 @@ class ToMany<EntityT> extends Object with ListMixin<EntityT> {
_track(element, 1);
}

/// Prepares to add the given target object to this relation.
///
/// To apply changes, call [applyToDb] or put the object with the ToMany.
/// For important details, see the notes about relations of [Box.put].
@override
void add(EntityT element) {
ArgumentError.checkNotNull(element, 'element');
Expand All @@ -121,6 +123,7 @@ class ToMany<EntityT> extends Object with ListMixin<EntityT> {
}
}

/// Like [add], but for multiple target objects.
@override
void addAll(Iterable<EntityT> iterable) {
iterable.forEach(_track);
Expand All @@ -132,8 +135,11 @@ class ToMany<EntityT> extends Object with ListMixin<EntityT> {
}
}

// note: to override, arg must be "Object", same as in the base class.
@override
/// Prepares to remove the target object from this relation.
///
/// To apply changes, call [applyToDb] or put the object with the ToMany.
/// For important details, see the notes about relations of [Box.put].
@override // note: to override, arg must be "Object", same as in the base class.
bool remove(Object? element) {
if (!_items.remove(element)) return false;
if (element != null) _track(element as EntityT, -1);
Expand Down
71 changes: 39 additions & 32 deletions objectbox/lib/src/relations/to_one.dart
Original file line number Diff line number Diff line change
@@ -1,49 +1,48 @@
import '../annotations.dart';
import '../box.dart';
import '../modelinfo/entity_definition.dart';
import '../native/transaction.dart';
import '../store.dart';

/// Manages a to-one relation, an unidirectional link from a "source" entity to
/// a "target" entity. The target object is referenced by its ID, which is
/// persisted in the source object.
///
/// You can:
/// - set [target]=null or [targetId]=0 to remove the relation.
/// - set [target] to an object to set the relation.
/// Call [Box<SourceEntity>.put()] to persist the changes. If the target
/// object is a new one (its ID is 0), it will be also saved automatically.
/// - set [targetId] to an existing object's ID to set the relation.
/// Call [Box<SourceEntity>.put()] to persist the changes.
/// A to-one relation of an entity that references one object of a "target" entity [EntityT].
///
/// Example:
/// ```
/// @Entity()
/// class Order {
/// final customer = ToOne<Customer>();
/// ...
/// }
/// ```
///
/// // Example 1: create a relation
/// final order = Order(...);
/// final customer = Customer();
/// order.customer.target = customer;
/// Uses lazy initialization.
/// The [target] object is only read from the database when it is first accessed.
///
/// // Or you could create the target object in place:
/// // order.customer.target = Customer()
/// Common usage:
/// - set the [target] object to create a relation.
/// When the object with the ToOne is put, if the target object is new (its ID is 0), it will be put as well.
/// Otherwise, only the target ID in the database is updated.
/// - set the [targetId] of the target object to create a relation.
/// - set [target] to `null` or [targetId] to `0` to remove the relation.
///
/// // attach() must be called when creating new instances. On objects (e.g.
/// // "orders" in this example) read with box.get() its done automatically.
/// order.customer.attach(store);
/// Then, to persist the changes [Box.put] the object with the ToOne.
///
/// // saves both [customer] and [order] in the database
/// ```
/// // Example 1: create a relation
/// order.customer.target = customer;
/// // or order.customer.targetId = customerId;
/// store.box<Order>().put(order);
///
///
/// // Example 2: remove a relation
///
/// // Example 2: remove the relation
/// order.customer.target = null
/// // ... or ...
/// order.customer.targetId = 0
/// // or order.customer.targetId = 0
/// store.box<Order>().put(order);
/// ```
///
/// The target object is referenced by its ID.
/// This [targetId] is persisted as part of the object with the ToOne in a special
/// property created for each ToOne (named like "customerId").
///
/// To get all objects with a ToOne that reference a target object, see [Backlink].
class ToOne<EntityT> {
/// Store-related configuration attached to this.
///
Expand Down Expand Up @@ -73,7 +72,9 @@ class ToOne<EntityT> {
}
}

/// Get target object. If it's the first access, this reads from DB.
/// Returns the target object or `null` if there is none.
///
/// [ToOne] uses lazy initialization, so on first access this will read the target object from the database.
EntityT? get target {
if (_value._state == _ToOneState.lazy) {
final configuration = _getStoreConfigOrThrow();
Expand All @@ -92,8 +93,11 @@ class ToOne<EntityT> {
return _value._object;
}

/// Set relation target object. Note: this does not store the change yet, use
/// [Box.put()] on the containing (relation source) object.
/// Prepares to set the target object of this relation.
/// Pass `null` to remove an existing one.
///
/// To apply changes, put the object with the ToOne.
/// For important details, see the notes about relations of [Box.put].
set target(EntityT? object) {
// If not attached, yet, avoid throwing and set the ID to unknown instead.
// If the targetId getter is used later, it will call this to re-try
Expand Down Expand Up @@ -123,8 +127,11 @@ class ToOne<EntityT> {
return _value._id;
}

/// Set ID of a relation target object. Note: this does not store the change
/// yet, use [Box.put()] on the containing (relation source) object.
/// Prepares to set the target of this relation to the object with the given [id].
/// Pass `0` to remove an existing one.
///
/// To apply changes, put the object with the ToOne.
/// For important details, see the notes about relations of [Box.put].
set targetId(int? id) {
id ??= 0;
if (id == 0) {
Expand Down

0 comments on commit 2bb12c3

Please sign in to comment.