1

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

Swisscheese
  • 571
  • 1
  • 5
  • 21
  • Hmm, don't see any obvious issue. Have you run `pub run build_runner build` after the upgrade? Also, how did you do the upgrade, any chance other packages got updated (though I don't see how that would influence this...)? Maybe, if other packages got updated, try pinning a previous version of objectbox that worked for you (1.0.0), run `pub run build_runner build` and check if the issue goes away? – vaind Aug 03 '21 at 09:13
  • Also you could try printing out the saved item (and its relations) directly after calling `.put()`. You can print out the `saveItem` variable but also try loading the data from the database and print it out – vaind Aug 03 '21 at 09:15
  • Also, It's not clear when do you call `saveCategorizedItem()` - I don't see the widget state being updated - how do you notify flutter to rebuild the widget, rerunning the query? – vaind Aug 03 '21 at 09:16
  • @vaind So I tried running build runner and then checking the store directly after saving, and this is what I got. What's being saved - https://i.ibb.co/4NZg13f/OnSave.jpg -- So everything appears correctly. This is directly after saving - https://i.ibb.co/gtDMtnw/PostSave.jpg . Everything is saved except for those 2 relations. Still confused as to what's causing the error – Swisscheese Aug 04 '21 at 02:09
  • The screenshots look good to me. You haven't accessed the related items so they haven't been loaded from the database. Both `ToOne` and `ToMany` do transparent lazy-loading. – vaind Aug 04 '21 at 08:35
  • @vaind So how do I go about accessing them correctly then? Because doing var test2 = test.elementAt(0).itemCategory.target; after that still yields null. – Swisscheese Aug 05 '21 at 02:06
  • Maybe try the following: `print(test[0].itemCategory.target);` then after that call, have another breakpoint and explore in the debugger what does `itemCategory._value._state` say - The only way I can think of you'd get `null` as a result from `.target` is that the given object doesn't exist in the database so the state would be `unresolvable` – vaind Aug 05 '21 at 08:28
  • @vaind You are correct, _ToOneState.unresolvable. But if the category itself is queried from the database, how is it not recognized? The categories are queried from the database and put into a list and shown in a dropdown. Once a selection is made from that dropdown, it sets the target as that category. So I'm guessing something is lost in translation there. The proper way would be to query the DB for that item and directly attach the returned query to the target? Curious why it worked before – Swisscheese Aug 06 '21 at 03:49
  • The current state as you're describing it should work just fine... So you're saying there's no chance categories are deleted, or anything... IDs on categories are assigned automatically by the database or self-assigned? If the latter and you are somehow attaching a category you haven't explicitly put, then it would explain why it's not saved. – vaind Aug 06 '21 at 06:24

1 Answers1

2

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();
}
vaind
  • 1,642
  • 10
  • 19