为啥 Flutter Floor DAO findAll 返回具有空 ID 的实体集?
Posted
技术标签:
【中文标题】为啥 Flutter Floor DAO findAll 返回具有空 ID 的实体集?【英文标题】:Why Flutter Floor DAO findAll returns entity set with null ids?为什么 Flutter Floor DAO findAll 返回具有空 ID 的实体集? 【发布时间】:2021-01-07 05:35:20 【问题描述】:这是一个使用 Floor(相当于 Jetpack 的 Room 包)的 Flutter 项目。 我有一个具有自动递增 id 的实体 (请注意,这是前空安全代码,在答案中,我现在从后空安全 sn-p 开始):
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);
到目前为止,我在我的应用中记录了五个活动,笨蛋。
_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?或者我为什么要告诉它,它必须默认存在,谁不想知道对象的主键?
【问题讨论】:
已投诉github.com/vitusortner/floor/issues/401 【参考方案1】:好的,这是因为我没有 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;
final int end;
Activity(
this.id,
required this.deviceName,
required this.deviceId,
required this.start,
this.end: 0,
);
我这里也加了这个Floor GitHub issue,看来以后可能会有注解:https://github.com/vitusortner/floor/issues/527
前零安全版本:
import 'package:meta/meta.dart';
class Activity
@PrimaryKey(autoGenerate: true)
int id;
@ColumnInfo(name: 'device_name')
@required
final String deviceName;
@ColumnInfo(name: 'device_id')
@required
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
。
【讨论】:
以上是关于为啥 Flutter Floor DAO findAll 返回具有空 ID 的实体集?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 std::round 提供返回 long 和 long long 的版本,而 std::floor、std::ceil、std::trunc 不提供?
PostgreSQL 中的快速随机行:为啥 time (floor(random()*N)) + (select * from a where id = const) 比 select where i