applyToDb method

void applyToDb({
  1. Store? existingStore,
  2. PutMode mode = PutMode.put,
  3. Transaction? tx,
})

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

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 StateError if the object that contains this ToMany has no ID assigned (it must have been put before).

Implementation

void applyToDb(
    {Store? existingStore, PutMode mode = PutMode.put, Transaction? tx}) {
  if (!_hasPendingDbChanges) return;

  final configuration = _getStoreConfigOrThrow();

  final relInfo = configuration.relInfo;
  if (relInfo.objectId == 0) {
    // The ID of the object owning this is required.
    throw StateError(
        "Can't store relation info for the target object with zero ID");
  }

  // Use given store, or obtain one via store configuration
  // (then store must be closed once done).
  final Store store = existingStore ??
      StoreInternal.attachByConfiguration(configuration.storeConfiguration);

  try {
    final ownedTx = tx == null;
    tx ??= Transaction(store, TxMode.write);
    try {
      _counts.forEach((EntityT object, count) {
        if (count == 0) return;
        final add = count > 0; // otherwise: remove
        var id = configuration.entity.getId(object) ?? 0;

        switch (relInfo.type) {
          case RelType.toMany:
            if (add) {
              if (id == 0) {
                id = InternalBoxAccess.put(
                    configuration.box(store), object, mode, tx);
              }
              InternalBoxAccess.relPut(configuration.otherBox(store),
                  relInfo.id, relInfo.objectId, id);
            } else {
              if (id == 0) return;
              InternalBoxAccess.relRemove(configuration.otherBox(store),
                  relInfo.id, relInfo.objectId, id);
            }
            break;
          case RelType.toOneBacklink:
            final srcField = relInfo.toOneSourceField(object);
            srcField.targetId = add ? relInfo.objectId : null;
            configuration.box(store).put(object, mode: mode);
            break;
          case RelType.toManyBacklink:
            if (add) {
              if (id == 0) {
                id = InternalBoxAccess.put(
                    configuration.box(store), object, mode, tx);
              }
              InternalBoxAccess.relPut(
                  configuration.box(store), relInfo.id, id, relInfo.objectId);
            } else {
              if (id == 0) return;
              InternalBoxAccess.relRemove(
                  configuration.box(store), relInfo.id, id, relInfo.objectId);
            }
            break;
          default:
            throw UnimplementedError();
        }
      });
      if (ownedTx) tx.successAndClose();
    } catch (ex) {
      // Is a no-op if successAndClose did throw.
      if (ownedTx) tx.abortAndClose();
      rethrow;
    }
  } finally {
    // If store was temporarily created, close it.
    if (existingStore == null) {
      store.close();
    }
  }

  _counts.clear();
  _addedBeforeLoad.clear();
}