Je construis ma première application en flutter, cette application utilise le sqlite database
. J'ai donc des modèles et des référentiels.
La mise en page de code:
J'ai 2 modèles (plus dans l'application finie) UserModel
, TimesheetModel
, ces deux prolongent un BaseModel
J'ai 2 référentiels (aura plus dans l'application finie) UserRepository
, TimesheetRepository
, ces deux prolongent BaseRepository
Ce que j'essaie de faire: j'aimerais avoir le code réutilisable tel que: getAll()
, countAll()
etc dans le BaseRepository
de la sorte que tous les référentiels qui prolongent la Le référentiel de base a cette fonctionnalité et tout ce que je devais faire est de définir le nom de la table et de définir le renvoi Model
.
L'erreur: comme vous pouvez le voir à partir de mon code parce que le type BaseRepository
renvoie un type BaseModel
Type, lorsque j'appelle la fonction all()
Fonction de la feuille de temps, je reçois l'erreur suivante : Tapez 'liste' n'est pas un sous-type de type 'Liste'
Je ne sais pas comment résoudre ce problème, des suggestions s'il vous plaît?
BaseerePositoire
abstract class BaseRepository {
final String table;
final model;
BaseRepository({this.table, this.model});
// Retrieve all the items
Future<List<BaseModel>> all() async {
final sql = '''SELECT * FROM $table''';
final data = await db.rawQuery(sql);
List<BaseModel> forms = List();
for (final node in data) {
final form = model.fromJson(jsonData: node);
forms.add(form);
}
return forms;
}
// Find an item by its ID
Future findById(int id) async {
final sql = '''SELECT * FROM $table
WHERE id = ?''';
List<dynamic> params = [id];
final data = await db.rawQuery(sql, params);
final form = model.fromJson(jsonData: data.first);
return form;
}
// Count all the items
Future<int> count() async {
final data = await db.rawQuery('''SELECT COUNT(*) FROM $table''');
int count = data[0].values.elementAt(0);
int idForNewItem = count++;
return idForNewItem;
}
// clear the table
Future<void> delete() async {
// truncate current database table
await db.rawQuery('''DELETE FROM $table''');
}
}
TIMESHEETTREPOSITORY
class TimesheetRepository extends BaseRepository {
String table = 'timesheets';
TimesheetModel model = new TimesheetModel();
// Search for a item by its name
Future<List<TimesheetModel>> findByDate(DateTime dateTime) async {
final String date = DateFormat("yyyy-MM-dd").format(dateTime);
final sql = '''SELECT * FROM $table WHERE timesheet_date = ?''';
List<dynamic> params = [date];
final data = await db.rawQuery(sql, params);
List<TimesheetModel> forms = List();
for (final node in data) {
final form = TimesheetModel.fromJson(jsonData: node);
forms.add(form);
}
return forms;
}
// Add a new item
Future<void> store(TimesheetModel timesheet) async {
final sql = '''INSERT INTO $table
(
user_id,
timesheet_date,
start_time,
end_time,
json,
is_uploaded
)
VALUES (?,?,?,?,?,?)''';
List<dynamic> params = [
timesheet.userId,
DateFormat("yyyy-MM-dd").format(timesheet.timesheetDate),
timesheet.startTime,
timesheet.endTime,
convert.json.encode(timesheet.json),
timesheet.is_uploaded,
];
final result = await db.rawInsert(sql, params);
DatabaseCreator.databaseLog('Add form', sql, null, result, params);
}
}
Lorsque vous appelez tous sur la feuille de temps
TimesheetRepository timesheet = TimesheetRepository();
timesheet.all();
Modèle de base
abstract class BaseModel {
fromJson();
}
Modèle de feuille de temps
class TimesheetModel extends BaseModel {
int id;
int userId;
DateTime timesheetDate;
String startTime;
String endTime;
Map json = {
"task": "",
"detail": "",
"notes": "",
};
bool is_uploaded;
TimesheetModel({
this.id,
this.userId,
this.timesheetDate,
this.startTime,
this.endTime,
this.json,
this.is_uploaded,
});
fromJson({Map<String, dynamic> jsonData}) {
return TimesheetModel(
id: jsonData['id'] as int,
userId: jsonData['user_id'] as int,
timesheetDate: timesheetDate,
startTime: jsonData['start_time'],
endTime: jsonData['end_time'],
is_uploaded: hasUploaded,
);
}
}
Je ne ferais pas l'analyse de Dijson comme vous le faites depuis que vous devez passer une instance vide du modèle pour pouvoir créer une instance valide du même objet. Mais pour que votre architecture fonctionne, vous devez faire des corrections:
1 - Faites de l'utilisation de génériques.
BasserePositoire
abstract class BaseRepository<T extends BaseModel> {
BaseRepository({this.table, this.model});
final String table;
final T model;
// Retrieve all the items
Future<List<T>> all() async {
final sql = '''SELECT * FROM $table''';
final data = await db.rawQuery(sql);
return data.map((node) {
return model.fromJson(jsonData: node);
}).toList();
}
Future<T> findById(int id) async {
final sql = '''SELECT * FROM $table
WHERE id = ?''';
final data = await db.rawQuery(sql, [id]);
return model.fromJson(jsonData: data.first);
}
// Count all the items
Future<int> count() async {
final data = await db.rawQuery('''SELECT COUNT(*) FROM $table''');
int count = data[0].values.elementAt(0);
int idForNewItem = count++;
return idForNewItem;
}
// clear the table
Future<void> delete() async {
// truncate current database table
await db.rawQuery('''DELETE FROM $table''');
}
}
2 - appelez correctement le super constructeur
TIMESHEETRÉPOSITOIRE
class TimesheetRepository extends BaseRepository<TimesheetModel> {
///IMHO you should not pass TimesheetModel instance here, it is really redundant
///you can create a parse class that receives the type and a json and does the
///trick
TimesheetRepository() : super(table: 'timesheets', model: TimesheetModel());
}
3 - Ajoutez le retour correct à votre méthode fromJson
abstract class BaseModel {
BaseModel fromJson({Map<String, dynamic> jsonData});
}
Je ne pouvais pas le tester intégré à la base de données, alors faites-moi savoir si cela fonctionne.
Pas exactement comme vous le code mais vous débarrasser de l'erreur: "liste" n'est pas un sous-type de type 'List'. Ceci est utile lorsque vous avez plusieurs tables avec plusieurs modèles qui héritent d'une super classe.
Permet de dire MySubClassA
et MySubClassB
hériter de MySuperClass
:
abstract class MySuperClass {
int id;
MySuperClass({this.id});
MySuperClass fromMap(Map<String, dynamic> map);
Map<String, dynamic> toMap();
}
class MySubClassA extends MySuperClass {
String name;
MySubClassA({int id, this.name}) : super(id: id);
@override
MySubClassA fromMap(Map<String, dynamic> map) {
return MySubClassA(
id: map['id'],
name: map['name'],
);
}
@override
Map<String, dynamic> toMap() {
Map<String, dynamic> myMap = Map<String, dynamic>();
myMap['id'] = id;
myMap['name'] = name;
return myMap;
}
}
class MySubClassB extends MySuperClass {
int postcode;
MySubClassB({int id, this.postcode}) : super(id: id);
@override
MySubClassB fromMap(Map<String, dynamic> map) {
return MySubClassB(
id: map['id'],
postcode: map['postcode'],
);
}
@override
Map<String, dynamic> toMap() {
Map<String, dynamic> myMap = Map<String, dynamic>();
myMap['id'] = id;
myMap['postcode'] = postcode;
return myMap;
}
}
Et une énumération avec le nom de la table de retour:
enum MyEnum { classA, classB }
extension MyEnumExtension on MyEnum {
static final tableNames = {
MyEnum.classA: 'table_a',
MyEnum.classB: 'table_b',
};
String get tableName => tableNames[this];
}
Dans votre base de donnéesHelper.dart pour obtenir la liste. Ce n'est pas le code complet, ajoutez votre propre singleton, initdb, crééeb:
Future<List<Map<String, dynamic>>> _getItemMapList(MyEnum myEnum) async {
Database db = await this.db;
var result = await db.query(myEnum.tableName);
return result;
}
Future<List<MySuperClass>> getItemList(MyEnum myEnum) async {
var itemMapList = await _getItemMapList(myEnum);
List<MySuperClass> itemList;
switch (myEnum) {
case MyEnum.classA:
itemList= List<MySubClassA>();
break;
case MyEnum.classB:
itemList= List<MySubClassB>();
break;
}
for (int i = 0; i < itemMapList.length; i++) {
switch (myEnum) {
case MyEnum.classA:
itemList.add(MySubClassA().fromMap(itemMapList[i]));
break;
case MyEnum.classB:
itemList.add(MySubClassB().fromMap(itemMapList[i]));
break;
}
}
return itemList;
}
Si vous créez la totalité de la méthode comme celle-ci? Je pense que Dart a besoin de ce type d'informations pour déduire le type. Pas tout à fait sûr
Future<List<T extends BaseModel>> all() async {