Skip to content

Query with linkMany does not provide value if there are no entities in ToMany relation #403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
orestesgaolin opened this issue Mar 23, 2022 · 4 comments
Labels
more info required Needs more info to become actionable. Auto-closed if no response.

Comments

@orestesgaolin
Copy link

orestesgaolin commented Mar 23, 2022

Basic info (please complete the following information):

  • ObjectBox version: 1.4.1
  • Flutter/Dart SDK: 2.10.3
  • Null-safety enabled: yes
  • Reproducibility: yes, sample available here
  • OS: Android, iOS, macOS
  • Device/Emulator: n/a

Steps to reproduce

Example available here

  1. Add several attachments to the first note by clicking on the attachment icon, don't add them to other notes

screenshot_2022-03-23_13 36 43

  1. Update query for a Note entity that has ToMany relation using ..linkMany(Entitiy_.relation)
  ObjectBox._create(this.store) {
    noteBox = Box<Note>(store);

    final qBuilder = noteBox.query()
      ..order(Note_.date, flags: Order.descending)
      // Comment to see it working
      ..linkMany(Note_.attachment);
    queryStream = qBuilder.watch(triggerImmediately: true);

    // Add some demo data if the box is empty.
    if (noteBox.isEmpty()) {
      _putDemoData();
    }
  }
  1. Hot restart the app
  2. Observe that it doesn't emit values which have no entities in the above relation

screenshot_2022-03-23_13 37 09

  1. Comment out line 23 in objectbox.dart file, hot restart the app, and observe this entity to be shown again

Expected behavior

Query using .linkMany should emit values also when there are no entities in the ToMany relation

Code

Sample available here https://github.com/objectbox/objectbox-dart/pull/402/files

@greenrobot-team
Copy link
Member

greenrobot-team commented Mar 28, 2022

Thanks for the report. However, why would you expect a query with the linkMany condition to also return objects without related objects? So basically being equivalent to the query without the linkMany condition?

Note that typically the link conditions are used with a condition on the related entity, so e.g.
linkMany(Note_.attachment, Attachment_.content.contains("something")).

@greenrobot-team greenrobot-team added more info required Needs more info to become actionable. Auto-closed if no response. and removed bug Something isn't working labels Mar 28, 2022
@orestesgaolin
Copy link
Author

I think I see where my expectation does not meet the reality - I don't pass any condition to the linkMany because I want all the possible related objects, even when there are no objects yet. The reason I want to use linkMany is that I want to be notified about changes to the related objects as well. In the example with notes and attachments if the attachment name changes, I want this to be reflected in the main query. Without using linkMany I won't be notified about the change of the linked attachment name (correct me if there's a different way to achieve that).

The workaround I use right now uses 2 instances of the same query. One of them without linkMany, the other with linkMany. Then I merge 2 streams with Rx.merge. In pseudo code it would be something like:

    final qBuilder1 = noteBox.query()
      ..order(Note_.date, flags: Order.descending)
      ..linkMany(Note_.attachment);
    final qBuilder2 = noteBox.query()
      ..order(Note_.date, flags: Order.descending);
    return Rx.merge([qBuilder1.watch(triggerImmediately: true), qBuilder2.watch(triggerImmediately: true)])
               .distinct();
Case Without linkMany With linkMany
0 related objects
1 related object ✅ but does not update when related object changed
remove last object ❌ does not update the list

@greenrobot-team
Copy link
Member

greenrobot-team commented Mar 29, 2022

Got it. In that case I recommend to write your own watch implementation. You can look at how it is done for queries and write a custom version that listens to the entity types you are interested in (e.g. replace queriedEntities with your own set):

Stream<Query<T>> watch({bool triggerImmediately = false}) {
final queriedEntities = HashSet<Type>();
_fillQueriedEntities(queriedEntities);
final query = build();
late StreamSubscription<void> subscription;
late StreamController<Query<T>> controller;
final subscribe = () {
subscription = _store.entityChanges.listen((List<Type> entityTypes) {
if (entityTypes.any(queriedEntities.contains)) {
controller.add(query);
}
});
};
controller = StreamController<Query<T>>(
onListen: subscribe,
onResume: subscribe,
onPause: () => subscription.pause(),
onCancel: () => subscription.cancel());
if (triggerImmediately) controller.add(query);
return controller.stream;
}

Then you can use any query you want with it.

@greenrobot-team greenrobot-team added more info required Needs more info to become actionable. Auto-closed if no response. and removed more info required Needs more info to become actionable. Auto-closed if no response. labels May 23, 2022
@github-actions
Copy link

Without additional information, we are unfortunately not sure how to resolve this issue. Therefore this issue has been automatically closed. Feel free to comment with additional details and we can re-open this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
more info required Needs more info to become actionable. Auto-closed if no response.
Projects
None yet
Development

No branches or pull requests

2 participants