isar / hive

Lightweight and blazing fast key-value database written in pure Dart.
Apache License 2.0
4.02k stars 401 forks source link

Saving Object with nested List of Objects #837

Open DieGlueckswurst opened 2 years ago

DieGlueckswurst commented 2 years ago

I have a Custom-Class which also has a field with another Custom-Class:

part 'hive_vitals_interface.g.dart';

@HiveType(typeId: 1)
class HiveVitals extends HiveObject {
  @HiveField(0)
  String? id;
  @HiveField(1)
  DateTime? date;
  @HiveField(2)
  List<HiveDiscomfort> otherDiscomfort;
  @HiveField(3)
  List<HiveDiscomfort> mentalDiscomfort;

  HiveVitals({
    this.id,
    this.date,
    this.otherDiscomfort = const [],
    this.mentalDiscomfort = const [],
  });
}

And my HiveDiscomforts-Class:

part 'hive_discomfort_interface.g.dart';

@HiveType(typeId: 2)
class HiveDiscomfort extends HiveObject {
  @HiveField(0)
  String? title;
  @HiveField(1)
  int? intensity;

  HiveDiscomfort({
    this.title,
    this.intensity,
  });
}

I am trying to save HiveVitals like this:

  static Future<void> addVitals(HiveVitals hiveVitals) async {
    final vitalsBox = getVitalsBox();

    await vitalsBox.put(hiveVitals.date!.toIso8601String(), hiveVitals);

  }

And retrieve it like this:

  static List<HiveVitals> getVitals() {
    Box<HiveVitals> box = getVitalsBox();
    List<HiveVitals> hiveVitals = box.values.toList();
    return hiveVitals;
  }

Problem:

I don't get any errors. In fact when saving my object and checking it in the debugger, everything is saved correctly. However when restarting the app, my List<HiveDiscomfort> fields are always empty again! But the rest of the HiveVitals-Fields are still saved correctly!?

What am I missing here? I don't get it... Any help is appreciated! Let me know if you need anything else!

Version

rikai-trongpq commented 2 years ago

Same issue here. Any solution?

tarektaamali commented 2 years ago

Any solution yet?

keezysilencer commented 2 years ago

Ensure that you are registering your HiveDiscomfort adapter. If the error still persists, let us see how you are creating your HIveVitals instance

canavci312 commented 2 years ago

any solution to this?

HemantNegi commented 2 years ago

Facing the same issue. below is my class

@HiveType(typeId: 10)
class ChatMessageModel {
  @HiveField(0)
  String? messageId;

  @HiveField(1)
  int? sender;

  @HiveField(2)
  List<int> recipient;

  @HiveField(3)
  String? text;

  @HiveField(4)
  DateTime? sentAt;

  @HiveField(5)
  List<ChatMessageModel> replies;

The problem is with replies field it comes out empty everytime.

Any solution please, or else I have to store it as json string (I don't want to do json parsing)

Clemens-Toegel commented 2 years ago

I had the same issue... I try to explain my solution based on this example. Given an object HiveVitals hiveVitals = HiveVitals(), whenever I tried to add something to the nested list of my custom object like hiveVitals.otherDiscomfort.add(), it was saved but not persisted (it was gone whenever I restarted the app). What I did was the following when I wanted to add something to the nested list:

List<HiveDiscomfort> tempList = [...hiveVitals.otherDiscomfort];
tempList.add(newData);
hiveVitals.otherDiscomfort = tempList;

That worked for me, now my data is persisted. I hope also your problems can be solved with that information.

@DieGlueckswurst I also tried to reproduce your problem to check if my solution would apply to you as well, but the code you have provided is too little.

Clemens-Toegel commented 2 years ago

My previous solution got me thinking and I think I know why nested lists are not persisted. It seems like hive is not checking for list equality and therefore never persist the changes, but uses the object as it is currently in memory. In issue #182 @leisim mentions:

When you add (or put) an object to Hive, it will not be copied but used as-is. That means if you alter the object instance from somewhere, you also change the object that Hive has in memory. This does not affect the persisted data.

So, that is why as long as the application runs the object is correctly in memory, but when the app is closed hive does not persist the data as it thinks that the data (here the lists) never changed, even though they changed (this is my guess now without looking further into the code of the hive package).

So that means the solution would be to check for equality of the lists in the equals method. For this example it would be:

@override
bool operator ==(Object other) =>
    identical(this, other) ||
    other is HiveVitals &&
        runtimeType == other.runtimeType &&
        id == other.id &&
        date == other.date &&
        listEquals(otherDiscomfort, other.otherDiscomfort) &&
        listEquals(mentalDiscomfort, other.mentalDiscomfort);

For me this solution works.

Kumah1 commented 5 months ago

Always make sure to convert your growable list to non-growable before saving it