问题描述
这是一个使用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
。