为什么Flutter Floor DAO findAll返回具有空ID的实体集?

问题描述

这是一个使用Floor(与Jetpack的Room相当的包装)的Flutter项目。 我有一个具有自动递增ID的实体:

const String ACTIVITIES_TABLE_NAME = 'activities';

@Entity(
  tableName: ACTIVITIES_TABLE_NAME,indices: [
    Index(value: ['start'])
  ],)
class Activity {
  @PrimaryKey(autoGenerate: true)
  int id;
  @ColumnInfo(name: 'device_name')
  final String deviceName;
  @ColumnInfo(name: 'device_id')
  final String deviceid;
  final int start;

  Activity({
    this.deviceName,this.deviceid,this.start,});
}

我有这个DAO:

@dao
abstract class ActivityDao {
  @Query('SELECT * FROM $ACTIVITIES_TABLE_NAME ORDER BY start DESC')
  Future<List<Activity>> findAllActivities();

  @insert
  Future<int> insertActivity(Activity activity);
}

到目前为止,在我的应用程序中,我记录了五项活动,hunky-dory。

_database =
    await $FloorAppDatabase.databaseBuilder('app_database.db').build();
...
    _activity =
       Activity(deviceName: device.name,deviceid: device.id.id,start: _lastRecord.millisecondsSinceEpoch);
    final id = await _database.activityDao.insertActivity(_activity);
    _activity.id = id;

然后在另一个视图中列出它们,但是存在一个潜伏的问题。

final data = await _database.activityDao.findAllActivities();

当我使用这种简单的简单方法查询实体时,数据库中的所有五个左右活动都将返回一个id字段,其中填充了null。这使该实体完全无用,因为由于缺少实际的ID,我想对其执行的任何其他操作都失败了。我在做错什么吗?

我大多数都具有MysqL,Postgres和非sqlite RDBMS的经验。据我了解,在sqlite中,每一行都有唯一的rowid,并且通过声明我的自动增量id主键字段,我基本上为该rowid加上了别名?不管是什么,我都需要身份证。它不能为空。


我正在调试Floor的内脏。

  Future<List<T>> queryList<T>(
    final String sql,{
    final List<dynamic> arguments,@required final T Function(Map<String,dynamic>) mapper,}) async {
    final rows = await _database.rawQuery(sql,arguments);
    return rows.map((row) => mapper(row)).toList();
  }

这时rows仍然正确地填写了ID,尽管行中的实体只是动态值的列表。 rows.map应该将它们映射到实体对象,并且由于某种原因而不能携带id?这可以是地板虫吗?


好吧,现在我看到在生成database.g.dart中,映射器没有ID:

  static final _activitiesMapper = (Map<String,dynamic> row) => Activity(
      deviceName: row['device_name'] as String,deviceid: row['device_id'] as String,start: row['start'] as int);

这说明了为什么id为null的原因。但这是生成代码,我如何告诉Floor我需要ID?还是我为什么要告诉它,认情况下它必须存在,谁不想知道对象的主键?

解决方法

好吧,这是因为我没有将id作为构造函数参数。我没有那个,因为它是一个自动递增字段,我不是确定它的人。但是,如果不将其作为构造函数参数,则生成的代码无法将其与映射器一起作为参数传递,因此将其从映射器中排除。

所以我添加了id作为构造函数参数:

class Activity {
  @PrimaryKey(autoGenerate: true)
  int id;
  @ColumnInfo(name: 'device_name')
  final String deviceName;
  @ColumnInfo(name: 'device_id')
  final String deviceId;
  final int start;

  Activity({
    this.id: null,this.deviceName,this.deviceId,this.start,});
}

编译器对null有点怀疑,但是在flutter packages pub run build_runner build之后,database.g.dart的映射器也有id