Objectbox Saved relation's target is null for ToOne and ToMany

Issue

Recently updated from 1.0.0 to 1.1.1 and my relation code quit working, I’m unsure what I missed exactly but everything up until the querying of the item seems to work correctly.

This is what I have, and I could really use some help figuring out what I missed

Store Creation:

  void initializeUserInventory() async {
    await getApplicationDocumentsDirectory().then((dir) {
      try {
        _quickSaveStore =
            Store(getObjectBoxModel(), directory: dir.path + '/quickSaveItems');
        _quickActionStore = Store(getObjectBoxModel(),
            directory: dir.path + '/quickSaveActions');
        _categorizedSaveStore = Store(getObjectBoxModel(),
            directory: dir.path + '/categorizedSaveItems');
        _itemCategoryStore = Store(getObjectBoxModel(),
            directory: dir.path + '/categorizedSaveCategories');
        _itemTagsStore = Store(getObjectBoxModel(),
            directory: dir.path + '/categorizedSaveTags');
      } catch (e) {
        print(e.toString());
      }
    }).whenComplete(() {
      // Must initialize everything else after completion of store initialization!
      _userQuickSaveBox = Box<InitialItem>(_quickSaveStore!);
      _quickActionSaveBox = Box<QuickSaveAction>(_quickActionStore!);
      _categorizedSaveBox = Box<InitialItem>(_categorizedSaveStore!);
      _itemCategoryBox = Box<ItemCategory>(_itemCategoryStore!);
      _itemTagsBox = Box<ItemTag>(_itemTagsStore!);
    });
  }

Here are the entity files:
InitialItem:

part 'initial_item.g.dart';

@JsonSerializable(explicitToJson: true)
@Entity()
class InitialItem {
  String? itemName;
  String? inc;
  DateTime cacheTime;
  DateTime? saveTime;


  @Id(assignable: true)
  int id;

  //#region Category
  //
  // Functions that are utilized for Saving the item by Category
  //
  /// Holds the count of how many items the vehicle/WO needs
  int? quantity;

  /// Any comments the user has added to the item
  String? userComment;

  /// Category that the item belongs too
  final itemCategory = ToOne<ItemCategory>();

  /// Allows adding a tag to the saved item
  final tags = ToMany<ItemTag>();

  //#endregion


  InitialItem(
      {this.id = 0,
      this.itemName,
      this.inc,
      this.quantity = 1,
      DateTime? cacheTime,
      DateTime? saveTime,
      this.userComment = '',})
      : cacheTime = cacheTime ?? DateTime.now(),
        saveTime = cacheTime ?? DateTime.now();
}

ItemCategory:

part 'item_category.g.dart';

@JsonSerializable(explicitToJson: true)
@Entity()
class ItemCategory {
  int id;
  String? categoryUid;
  String? userUid;
  String? categoryName;
  String? categoryComment;

  @Backlink()
  final items = ToMany<InitialItem>();

  ItemCategory(
      {this.id = 0,
      this.userUid,
      this.categoryName,
      this.categoryUid,
      this.categoryComment});
}

ItemTag:

part 'item_tag.g.dart';

@JsonSerializable(explicitToJson: true)
@Entity()
class ItemTag {
  int id;
  String? name;

  /// Only used for FilterChip display, not saved in any database
  @Transient()
  bool isSelected;
  String? uid;

  ItemTag({this.id = 0, this.name, this.isSelected = false, this.uid});
}

The Tags and the Categories are already created by the user and saved in their boxes. An item is passed into the view, the user can add tag(s) to the item, and can select a category to save the item under.

  /// Attaches the tags that the user selected to the item for saving
  void attachTagsToItem() {
    // Clear all previous tags before adding the selected tags
    savingItem?.tags.clear();
    savingItem?.tags.addAll(enabledTagList);
  }

The item then has the selected category written to it’s toOne target and it is saved — savingItem correctly has everything in it right here

  bool saveCategorizedItem() {
    if (selectedCategory != null) {
      // Set the item category
      savingItem!.itemCategory.target = selectedCategory;

      _userInventoryService.addCategorizedItemToLocal(savingItem!);

      return true;
    } else {
      return false;
    }
  }

Where it’s saved — at this point, everything checks out. I can debug and see the tags and information in their variable, and I can see the Category and it’s information in itemCategory.

  void addCategorizedItemToLocal(InitialItem saveItem) {
    _categorizedSaveBox.put(saveItem);
    print('Item saved to categorized database');
  }

Item on Saving

Later on, I query every item that is saved in order to group them into lists. And at this point It only returns the InitialItem, and it doesn’t pull the relation data with it. Both toOne and toMany’s targets are null.

  /// Returns all the of Items that have been categorized and saved
  List<InitialItem> getAllCategorizedItems() => _categorizedSaveBox.getAll();

------------------------------------------------------------------------------------------
Calling the query in the View Provider's class
  void getCategorizedItems() {
    _categorizedSaveList = _userInventoryService.getAllCategorizedItems();
    notify(ViewState.Idle);
  }

I then attempt to build the list using the returned query. element.itemCategory.target returns null, and the same goes for the tags. As I stated, this all was previously working in version 1.0.0, and it fails after upgrading, with no other changes made. Is there something wrong with the query in general? I can view the relations in the debug window so I’m assuming that is set correctly, it just doesn’t appear to be pulling the objects with the original query.
Can anyone shed some light on what I’m doing wrong?

  Widget categorizedList(BuildContext context) {
    final saveProvider =
        Provider.of<UserInventoryProvider>(context, listen: true);
    return GroupedListView<dynamic, String>(
      physics: const BouncingScrollPhysics(),
      elements: saveProvider.categorizedSaveList,
      groupBy: (element) => element.itemCategory.target!.categoryName,
      groupComparator: (d1, d2) => d2.compareTo(d1),
      groupSeparatorBuilder: (String value) => Padding(
        padding: const EdgeInsets.all(8.0),
        child: Text(value,
            textAlign: TextAlign.center,
            style: TextStyles.kTextStyleWhiteLarge),
      ),
      indexedItemBuilder: (c, element, index) {
        return Container();
      },
    );
  }

Item directly after saving, queried from store

Solution

After all the talks in the comments, I’ve finally noticed you initialize multiple stores. Effectively, you’re working with multiple standalone databases, therefore the relations couldn’t work as expected. Your initializeUserInventory() should look something like:

void initializeUserInventory() async {
  _store = await openStore(); // new shorthand in v1.1, uses getApplicationDocumentsDirectory()
  _userQuickSaveBox = _store.box();
  _quickActionSaveBox = _store.box();
  _categorizedSaveBox = _store.box();
  _itemCategoryBox = _store.box();
  _itemTagsBox = _store.box();
}

Answered By – vaind

Answer Checked By – Timothy Miller (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *