objectbox / objectbox-dart

Flutter database for super-fast Dart object persistence
https://docs.objectbox.io/getting-started
Apache License 2.0
1.03k stars 118 forks source link

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

Closed orestesgaolin closed 2 years ago

orestesgaolin commented 2 years ago

Basic info (please complete the following information):

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 commented 2 years ago

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")).

orestesgaolin commented 2 years ago

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 commented 2 years ago

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):

https://github.com/objectbox/objectbox-dart/blob/d72f51e325b02f77b36b9c8e8515d3bdec8e4c5b/objectbox/lib/src/native/query/builder.dart#L33-L53

Then you can use any query you want with it.

github-actions[bot] commented 2 years ago

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.