web-dev-qa-db-fra.com

Héritage de la classe flutter

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,
    );
  }
}

9
Billy Mahmood

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.

3
haroldolivieri

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;
}
0
Tuss

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 {
0
Rodrigo Bastos