I am trying to use a single model for both storing the data locally using Isar, and also for using with Retrofit for REST API requests.
But Isar requires all the Linked classes to be defined with the datatype IsarLink<MyClassName> where JsonSerializable requires them with MyClassName as the datatype.
#Collection()
#JsonSerializable()
class UserGroup {
#JsonKey(ignore: true)
Id localId = Isar.autoIncrement; // you can also use id = null to auto increment
#ignore
#JsonKey(name: "_id")
String? id;
String name;
String description;
#ignore
Domain? domain;
#ignore
UserGroupPermissions permissions;
#ignore
Organization? organization;
#JsonKey(ignore: true)
IsarLink<Organization?> organization = IsarLink<Organization?>();
UserGroup({
this.id,
required this.name,
required this.description,
this.domain,
required this.permissions,
this.organization,
});
factory UserGroup.fromJson(Map<String, dynamic> json) => _$UserGroupFromJson(json);
Map<String, dynamic> toJson() => _$UserGroupToJson(this);
}
Other than defining two variables like IsarLink<MyClassName> localOrganization with #JsonKey(ignore: true) for Isar and MyClassName with #ignore for JsonSerializable is there any other way to use a single variable for working with both of them?
Having to define two variables almost everywhere to support both of the generators makes the code look really messy
Related
I have a class with the following attributes in Dart
class StartValue {
final int id;
final String firstName;
final String lastName;
StartValue({this.id, this.firstName, this.lastName})
}
and Ill initiate that classe with the values:
StartValue(
id: 1,
firstName: 'First',
lastName: 'LastName'
)
The question is what kind of validation i need to do to never instance a class StartValue with the NAME = 'First' again? Assuming I can only instantiate the class once with firstName = 'First'.
How do I do an instance validation to verify that each instance does not contain the firstName = "First" ?
I have to do something like:
StartValues.contains("First")
Keep in mind that I have almost 1000 classes instantiated, so I will have to check one by one if the value "First" contains in each class, this is my question
You have to iterate through every class to check if the firstName is taken, but I recommend using the == operator instead of .contains(). Why would you have 1000 instances? Can you put us in context?
Use a class-static Set of all ids seen so far. This will be quick to identify whether an item has already been generated.
Something like:
class Person {
final int id;
final String name;
static var seenIds = <int>{};
Person({
required this.id,
required this.name,
}) {
if (!seenIds.add(id)) throw ArgumentError('id $id already seen');
}
}
Keeping thousands of instances / names in memory is bad design as they are way too many instances / names you don't need at that moment. You go for local sql database like sqflite or you go for cloud database like Cloud Firestore to fetch the user you need and validate it.
If you still want to do it in-memory you can use a factory constructor, a private constructor and a static HashSet to check user instances.
If you need explanation then comment below. Full code example:
import 'dart:collection';
class Person {
final int id;
final String firstName;
final String lastName;
static HashSet<String> allNames = HashSet<String>();
factory Person({
required int id,
required String firstName,
required String lastName,
}) {
if (!allNames.add(firstName)) {
throw ArgumentError("Person with firstname $firstName already exists");
}
return Person._(id: id, firstName: firstName, lastName: lastName);
}
Person._({
required this.id,
required this.firstName,
required this.lastName
});
}
I use floor as SQLite abstraction in a flutter app.
I want to save a person with a list of presents, so I created a ForeignKey (as mentioned here) and mapped child id to parent presents, but I get the error Column type is not supported for List<Present> when I run the generator via flutter packages pub run build_runner build.
I have present and person as entities.
#entity
class Present {
#PrimaryKey(autoGenerate: true)
int? id;
String name;
double? price;
Present({this.id, required this.name, this.price});
}
#Entity(tableName: 'Person', foreignKeys: [
ForeignKey(childColumns: ['id'], parentColumns: ['presents'], entity: Present)
])
class Person {
#PrimaryKey(autoGenerate: true)
int? id;
String name;
List<Present> presents;
Person({
this.id,
required this.name,
required this.presents,
});
}
I'm writing a flutter app and i need to serialise a class to json. The class is :
#HiveType(typeId: 0)
#JsonSerializable()
class CartItem extends HiveObject {
#HiveField(1)
String item_id;
#HiveField(2)
String name;
#HiveField(3)
SelectionsList selections;
#HiveField(4)
String special_instructions;
#HiveField(5)
int quantity;
#HiveField(6)
double amount;
#HiveField(7)
#JsonKey(ignore: true)
MenuItem item;
CartItem(this.item_id, this.name, this.selections, this.quantity, this.special_instructions, this.amount, this.item);
}
however, due to the item field being ignored (intended), when i try to generate the .g.dart file, this error is thrown. Cannot populate the required constructor argument: item. It is assigned to an ignored field. I still need it to be in the constructor though, So is there a workaround for this?
So I managed to get this working. Not sure if it is the correct way but if it helps you out then great.
#HiveType(typeId: 0)
#JsonSerializable()
class CartItem extends HiveObject {
...
#HiveField(7)
#JsonKey(ignore: true)
MenuItem item;
CartItem(this.item_id,
this.name, this.selections, this.quantity, this.special_instructions, this.amount,
[this.item = MenuItem.empty()]);
}
You have to set the constructor entry an optional positional and give it a default value.
You can also make it nullable and leave out the default on the constructor item.
I'm asking a question and not found an similar post for this.
I explain, I use json_serializable, but webservice provide some information of the same type of object by with different name keys, exemple :
#JsonSerializable(explicitToJson: true)
class Group {
Group(
this.id,
this.name,
this.owner,
this.description);
int id;
String name;
User owner; //Here owner are only "id" and "name"
String? description;
...
}
#JsonSerializable()
class User {
User(this.uid, this.nom, this.mail, this.prenom);
String? uid;
late String mail;
String nom;
String? prenom;
...
So "id" and "uid" are different key but for same value, and same things for "name" and "nom".
There is any way for indicate to generator this can be different name of key for same value ..?
My solution is to set two different variable witch one will can be NULL
Suppose there are two models User and City
#JsonSerializable()
class User {
int id;
String name;
City? city;
List<Map<String, City>>? listMapCity;
}
#JsonSerializable()
class City {
int id;
String name;
}
Now suppose during API call, we've got a user model but in the city object model, we only get id not name. Something like this
{
"id": 5,
"name": "Matthew",
"city": {
"id": 12
}
}
But due to the default nature of json_serializable and json_annotation.
This JSON is not mapped to the User model, during mapping, it throws the exception.
type Null is not a subtype of type String. (because here name key is missing in city object)
But as we already declared in the User object that City is optional, I wanted that it should parse the User JSON with city and listMapCity to be null.
Any help or solution would be really appreciated, Thank you
You need to set the includeIfNull flag to false to have the autogenerated code handle nulls correctly.
#JsonSerializable(includeIfNull: false)
The property should be declared with a ? as per your example.
You need to have a default constructor on your JsonSerializable User class. Then, if name should be nullable, declare it with a nullable String? name;
Here's the updated User class.
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
#JsonSerializable()
class User {
int id;
String name;
City? city;
List<Map<String, City>>? listMapCity;
User({required this.id, required this.name, this.city, this.listMapCity});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
#JsonSerializable()
class City {
int id;
String name;
City({required this.id, required this.name});
}