objectbox / objectbox-dart

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

Example for custom type seems to be backwards in implementation #533

Closed ChickenF622 closed 11 months ago

ChickenF622 commented 1 year ago

Was running into an issue where the start hour and minute were not getting saved to the database. According to the example it seems that the non-database friendly value can be property as long as it's marked as @Transient, and getters/setters can be used to break it down into a more database friend value (in this case int). If I were to reverse the implementation where the minute and hour values are just values and the startTime TimeOfDay is provided via getter/setters the values are stored properly.

Link to documentation: https://docs.objectbox.io/advanced/custom-types#convert-annotation-and-property-converter

Example of code that works

@Entity
class Event {
  int id = 0;
  int startTimeHour = 0;
  int startTimeMinute = 0;

  @Transient()
  TimeOfDay get startTime {
    return TimeOfDay(hour: startTimeHour, minute: startTimeMinute);
  }

  set startTime(TimeOfDay startTime) {
    startTimeHour = startTime.hour;
    startTimeMinute = startTime.minute;
  }
}

Example of code that doesn't work, and follows the pattern in the example

@Entity
class Event {
  int id = 0;
  @Transient
  TimeOfDay startTime;
  Event({required this.startTime});

  int get startTimeHour {
    return startTime?.hour;
  }

  set startTimeHour(int hour) {
    startTime = startTime.replacing(hour: hour);
  }

  int get startTimeMinute {
    return startTime.minute;
  }

  set startTimeMinute(int minute) {
    startTime = startTime.replacing(minute: minute);
  }
}
greenrobot-team commented 1 year ago

The first example you have given actually only works because currently annotations are not recognized on getters and setters (see #392). It also prints a warning when running flutter pub run build_runner build --delete-conflicting-outputs:

[WARNING] objectbox_generator:resolver on lib/model.dart:
  Skipping property 'startTime': type 'TimeOfDay' not supported, consider creating a relation for @Entity types (https://docs.objectbox.io/relations), or replace with getter/setter converting to a supported type (https://docs.objectbox.io/advanced/custom-types).

What is broken with the second example is the initialization. ObjectBox requires a constructor that supplies all stored properties so it can restore an object. E.g. this works:

@Entity()
class Event {
  int id = 0;

  @Transient()
  TimeOfDay startTime = const TimeOfDay(hour: 0, minute: 0);

  int get startTimeHour {
    return startTime.hour;
  }

  set startTimeHour(int hour) {
    startTime = startTime.replacing(hour: hour);
  }

  int get startTimeMinute {
    return startTime.minute;
  }

  set startTimeMinute(int minute) {
    startTime = startTime.replacing(minute: minute);
  }

  Event(this.id, int startTimeHour, int startTimeMinute) {
    this.startTimeHour = startTimeHour;
    this.startTimeMinute = startTimeMinute;
  }
}

Let me know if you have more questions. Otherwise close this issue (it will auto-close if no response in 2 weeks).

ChickenF622 commented 1 year ago

I may be missing something, but the example here: https://docs.objectbox.io/advanced/custom-types#convert-annotation-and-property-converter. Doesn't provide a constructor like that, so I think the example should be updated. I do see the note about the constructor here: https://docs.objectbox.io/entity-annotations#objectbox-database-persistence-with-entity-annotations, but it is on an entirely separate page. I think it would be helpful if the example reflected that. If you don't agree I'll close the issue. Thanks for taking a look at this.

greenrobot-team commented 1 year ago

Doesn't provide a constructor like that

Ah sorry. This is the other possibility: make fields nullable (Role? role;, int? get dbRole and set dbRole(int? value) in this case) so they do not require initialization. ObjectBox will then set the field directly to construct a new object.

github-actions[bot] commented 11 months 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.