【问题标题】:Flutter Class inheritanceFlutter 类继承
【发布时间】:2019-09-04 09:51:16
【问题描述】:

我正在使用 Flutter 构建我的第一个应用程序,该应用程序使用 sqlite database。所以我有模型和存储库。

代码布局:

我有 2 个模型(在完成的应用程序中会有更多)UserModelTimesheetModel,它们都扩展了 BaseModel

我有 2 个存储库(在完成的应用程序中会有更多)UserRepositoryTimesheetRepository,它们都扩展了 BaseRepository

我正在尝试做的事情: 我希望在BaseRepository 中有可重用的代码,例如:getAll()countAll() 等,这样扩展基本存储库的所有存储库都具有此功能,我需要做的就是设置表名和设置返回的Model

错误: 正如您从我的代码中看到的那样,因为BaseRepository 正在返回BaseModel 类型,所以当我在时间表对象上调用all() 函数时,我收到以下错误:类型“列表”不是“列表”类型的子类型'

我不知道如何解决这个问题,请问有什么建议吗?

基础存储库

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

时间表存储库

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


}

在 Timesheet 上调用 all 时

TimesheetRepository timesheet = TimesheetRepository();
timesheet.all();

基础模型

abstract class BaseModel {
  fromJson();
}

时间表模型


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

【问题讨论】:

  • 请出示BaseModel和TimeSheetModel的代码
  • 嘿@RodrigoBastos 谢谢你的回复,我现在已经添加了你要求的代码
  • 我多次遇到同样的问题,但没有找到解决方案。我不知道在 Dart 中有什么好的方法。
  • 我希望有人可以发布答案或至少是一个好的解决方法
  • 我也有这个问题。有人吗?

标签: class inheritance flutter dart


【解决方案1】:

我不会像您那样从Json 解析,因为您需要传递模型的空实例才能创建同一对象的有效实例。但是为了让你的架构正常工作,你需要做一些更正:

1 - 使用泛型。

BaseRepository

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 - 正确调用超级构造函数

TimesheetRepository

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 - 将正确的返回添加到您的 fromJson 方法

abstract class BaseModel {
  BaseModel fromJson({Map<String, dynamic> jsonData});
}

我无法测试它与数据库的集成,因此请告诉我是否可行。

【讨论】:

  • 谢谢,我今天要实现这个,会回来告诉你我是怎么做的,不过看起来很有希望。
  • 嗨,我尝试了代码,没有收到任何错误,但是这个脚本返回 null dart return data.map((node) { model.fromJson(jsonData: node); }).toList(); 我的数据库中有 2 条记录,所以我得到了 [null, null]
【解决方案2】:

如果你像这样创建 all 方法?我认为飞镖需要这种类型的信息来推断类型。不过不太确定

Future<List<T extends BaseModel>> all() async {

【讨论】:

  • 这会在这个错误中返回The name T isnt a type so it cant be used as a type
【解决方案3】:

与您的代码不完全一样,但摆脱了错误:“List”不是“List”类型的子类型。当您有多个表以及从超类继承的多个模型时,这很有用。

假设MySubClassAMySubClassB 继承自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;
  }
}

还有一个带有扩展名的枚举来返回表名:

enum MyEnum { classA, classB }

extension MyEnumExtension on MyEnum {
  static final tableNames = {
    MyEnum.classA: 'table_a',
    MyEnum.classB: 'table_b',
  };

  String get tableName => tableNames[this];
}

在你的databasehelper.dart 中获取列表。这不是完整的代码,添加你自己的singleton,initDb,createDb:

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

【讨论】:

    【解决方案4】:

    我的回复可能会迟到,但是用这个方法:

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

    您需要添加:return (model.fromJson(jsonData: node) as T)以避免错误:List&lt;BaseModel&gt; is not a subtype of List&lt;TimesheetModel&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-12
      • 2018-05-23
      • 2015-03-14
      • 2010-11-08
      相关资源
      最近更新 更多