objectbox/objectbox-dart

JSON Serialization with relations

badayumut opened this issue · 4 comments

Is there an existing issue?

Build info

  • objectbox version: [e.g. 2.3.1]
  • Flutter/Dart version: [e.g. 3.1.0, see flutter --version or dart --version]
  • Build OS: [e.g. Ubuntu 22.04 | Windows 11 | macOS 10.16 ]
  • Deployment OS or device: [e.g. Android 14 | iOS 16.4 | Galaxy S23 ]

Steps to reproduce

I'm working on exporting the model to json and retrieving it, and I reviewed the example here. I tried to implement it to my own model in the same way. Simple parameters (String, int) in the model are saved in json, but I cannot extract relations. Is there something I missed?
I'm trying to transfer the model as it is with relations and get it back.
https://github.com/objectbox/objectbox-dart/blob/main/generator/integration-tests/part-partof/lib/json.dart

import 'package:json_annotation/json_annotation.dart';
import 'package:objectbox/objectbox.dart';

part 'example_model.g.dart';

@Entity()
@JsonSerializable()
class Book {
  @Id()
  int id = 0;

  String content;


  @_PersonRelToOneConverter()
  final author = ToOne<Person>();

  Book({
    required this.content,
  });

  factory Book.fromJson(Map<String, dynamic> json) => _$BookFromJson(json);

  Map<String, dynamic> toJson() => _$BookToJson(this);
}

@Entity()
@JsonSerializable()
class Person {
  @Id()
  int id = 0;

  String name;

  @_BookRelToManyConverter()
  final books = ToMany<Book>();

  Person({
    required this.name,
  });

  factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);

  Map<String, dynamic> toJson() => _$PersonToJson(this);
}

class _PersonRelToOneConverter
    implements JsonConverter<ToOne<Person>, Map<String, dynamic>?> {
  const _PersonRelToOneConverter();

  @override
  ToOne<Person> fromJson(Map<String, dynamic>? json) => ToOne<Person>(
      target: json == null ? null : Person.fromJson(json));

  @override
  Map<String, dynamic>? toJson(ToOne<Person> rel) => rel.target?.toJson();
}

class _BookRelToManyConverter
    implements JsonConverter<ToMany<Book>, List<Map<String, dynamic>>?> {
  const _BookRelToManyConverter();

  @override
  ToMany<Book> fromJson(List<Map<String, dynamic>>? json) =>
      ToMany<Book>(
          items: json == null
              ? null
              : json.map((e) => Book.fromJson(e)).toList());

  @override
  List<Map<String, dynamic>>? toJson(ToMany<Book> rel) =>
      rel.map((Book obj) => obj.toJson()).toList();
}

Expected behavior

should be able to access relations after created from json

Actual behavior

relations missing after json serialization

Code

    Person author = Person(name: "author");

    Book book1 = Book(content: "content1")..author.target = author;
    Book book2 = Book(content: "content2")..author.target = author;

    Person person = Person(name: "person");
    person.books.add(book1);
    person.books.add(book2);
    
    final book1FromJson = Book.fromJson(book1.toJson());
    final personFromJson = Person.fromJson(person.toJson());

    print(book1FromJson.author.target?.name); // null

    print(personFromJson.books.length); // 0

Logs, stack traces

TODO Add relevant logs, a stack trace or crash report.

Logs
[Paste your logs here]

From what I can see the constructors of the classes you have given do not have parameters for the relation fields:

  Book({
    required this.content, // no parameter for author
  });

  Person({
    required this.name, // no parameter for books
  });

In any case, I would strongly recommend to use a different model for the database and the JSON serializer and map between them. It would avoid this issue and also make any future changes easier to handle.

Let me know if this resolves your issue!

I was about to update the issue with that the generated example_model.g.dart did not have the rel convertion methods. Anyway I couldn't make it work this way. So i implemented a custom map for to-from methods. I think it's the best way to it with more control. Thanks!