objectbox / objectbox-dart

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

query.Watch() doesn't return latest data #473

Closed bahadirarslan closed 2 years ago

bahadirarslan commented 2 years ago

My app's home screen has a PageView for listening the data from ObjectBox. Also, there is another screen for adding data to the same store.

After putting my new entity to store, I want to see updated PageView when I pop from add screen to home screen.. To achieve this I implemented .watch() feature of ObjectBox like example.

Here is the Stream created.

Stream<List<FlightLog>> getRecentLogsFromLocal() {
    final builder = box.query()..order(FlightLog_.dbAddDate, flags: Order.descending);
    return builder.watch(triggerImmediately: true).map((query) => query.find().sublist(0, box.count(limit: 10)));
  }

This event successfully triggers when I inserted a new entity to store but query.find() returns data without new entity. If I hot-restart my app I can see the correct data. But I don't want to tell users to restart the app if they want to see the latest data on the home screen. So this is not working for me.

Am I doing something wrong?

Edit: According to my experiments the problem is not about watch method. The problem is ordering with dbAddDate column. I created a standalone example to understand better. I will update if I find more.

Update: I tried to recreate the bug on official example but I couldn't. It looks like system works as expected but somehow I have got a problem with ordering by date. I'm still investigating the issue, if I can find more I will update this again.

greenrobot-team commented 2 years ago

Looks like you double-posted on Stack Overflow (it would be nice if you could avoid that, saves us time), so also sharing here:

Maybe try to use a query limit instead of the sublist + count methods: query..limit = 10. Otherwise, I don't see any issue with the code snippet you have given.

If you suspect ordering is the issue, we welcome a reproduceable example!

bahadirarslan commented 2 years ago

Hello, first of all, I am sorry for the double post. I deleted it from SO.

About the situation, the limit is not a problem because now I use the id column for this order and it works as expected. But somehow it is not working with dbAddDate field.

Current method is like below

  Stream<List<FlightLog>> getRecentLogsFromLocal() {
    final builder = box.query()..order(FlightLog_.id, flags: Order.descending);
    return builder.watch(triggerImmediately: true).map((query) {
      return query.find().sublist(0, box.count(limit: 10));
    });
  }

dbAddDate field:

@JsonKey(name: "AddDate", toJson: toFullFormatDate)
  @Transient()
  DateTime addDate = DateTime.now();
  @JsonKey(ignore: true)
  int get dbAddDate => addDate.millisecondsSinceEpoch;
  @JsonKey(ignore: true)
  set dbAddDate(int value) {
    addDate = DateTime.fromMillisecondsSinceEpoch(value, isUtc: true);
  }

Changing from dbAddDate to id may be solved this situation but I have another function that returns the last inserted entity by ordering it by the Version column.

  DateTime? getLastVersionDate() {
    final query = box.query(FlightLog_.dbStatus.equals(RecordStatus.synced.code))..order(FlightLog_.dbVersion, flags: Order.descending);
    final log = query.build().findFirst();
    if (log == null) {
      return DateTime.fromMillisecondsSinceEpoch(0);
    }
    return DateTime.fromMillisecondsSinceEpoch(log.dbVersion, isUtc: true);
  }

Here is the Version column

  @JsonKey(name: "Version", toJson: toFullFormatDate)
  @Transient()
  DateTime version = DateTime.now();
  @JsonKey(ignore: true)
  int get dbVersion => version.millisecondsSinceEpoch;
  @JsonKey(ignore: true)
  set dbVersion(int value) {
    version = DateTime.fromMillisecondsSinceEpoch(value, isUtc: true);
  }

I need to retrieve the greatest Version value but I always retrieve the second greatest one. But I couldn't change this function to id column order so I need to figure out what is wrong.

greenrobot-team commented 2 years ago

Thanks for the additional details! I just wrote a quick test adding a version property, also using a custom getter/setter.

// dbVersion property
@Transient()
DateTime version = DateTime.now();
int get dbVersion => version.millisecondsSinceEpoch;
set dbVersion(int value) {
  version = DateTime.fromMillisecondsSinceEpoch(value, isUtc: true);
}

// test code
box.put(TestEntity()..dbVersion = 1);
box.put(TestEntity()..dbVersion = 2);
var query = (box.query()
      ..order(TestEntity_.dbVersion, flags: Order.descending))
    .build();
final result = query.findFirst()!;
expect(result.dbVersion, 2);
box.put(TestEntity()..dbVersion = 3);
final result2 = query.findFirst()!;
expect(result2.dbVersion, 3);
query.close();

However, it works as expected. As said, it would be helpful if you can provide a test or an example app that reproduces this.

Feel free to play with our tests suite as well.

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.