You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Moor 如何获取nullsafe类型的GeneratedColumn?

问题描述

无论GeneratedColumn的定义中是否配置nullable(),其泛型数据类型始终为可空类型,即便使用TextColumn或Column<String>(及其他同类型定义)也无差异,示例如下:

示例代码

手写的db.dart定义

import 'package:moor/moor.dart';

part 'db.g.dart';

class FooTable extends Table {
  Column<String> get id => text()();

  Column<int> get someNumber => integer()();

  Column<DateTime> get someDate => dateTime()();
}

@UseMoor(tables: <Type>[FooTable])
class Db extends _$Db {
    // ...
}

自动生成的db.g.dart对应实现

class $FooTableTable extends FooTable with TableInfo<$FooTableTable, FooTableData> {
  final GeneratedDatabase _db;
  final String? _alias;
  $FooTableTable(this._db, [this._alias]);
  final VerificationMeta _idMeta = const VerificationMeta('id');
  late final GeneratedColumn<String?> id = GeneratedColumn<String?>(
      'id', aliasedName, false,
      typeName: 'TEXT', requiredDuringInsert: true);
  final VerificationMeta _someNumberMeta = const VerificationMeta('someNumber');
  late final GeneratedColumn<int?> someNumber = GeneratedColumn<int?>(
      'some_number', aliasedName, false,
      typeName: 'INTEGER', requiredDuringInsert: true);
  final VerificationMeta _someDateMeta = const VerificationMeta('someDate');
  late final GeneratedColumn<DateTime?> someDate = GeneratedColumn<DateTime?>(
      'some_date', aliasedName, false,
      typeName: 'INTEGER', requiredDuringInsert: true);
  @override
  List<GeneratedColumn> get $columns => [id, someNumber, someDate];
  @override
  String get aliasedName => _alias ?? 'foo_table';
  @override
  String get actualTableName => 'foo_table';
  @override
  VerificationContext validateIntegrity(Insertable<FooTableData> instance,
      {bool isInserting = false}) {
    final context = VerificationContext();
    final data = instance.toColumns(true);
    if (data.containsKey('id')) {
      context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
    } else if (isInserting) {
      context.missing(_idMeta);
    }
    if (data.containsKey('some_number')) {
      context.handle(
          _someNumberMeta,
          someNumber.isAcceptableOrUnknown(
              data['some_number']!, _someNumberMeta));
    } else if (isInserting) {
      context.missing(_someNumberMeta);
    }
    if (data.containsKey('some_date')) {
      context.handle(_someDateMeta,
          someDate.isAcceptableOrUnknown(data['some_date']!, _someDateMeta));
    } else if (isInserting) {
      context.missing(_someDateMeta);
    }
    return context;
  }

  @override
  Set<GeneratedColumn> get $primaryKey => <GeneratedColumn>{};
  @override
  FooTableData map(Map<String, dynamic> data, {String? tablePrefix}) {
    return FooTableData.fromData(data, _db,
        prefix: tablePrefix != null ? '$tablePrefix.' : null);
  }

  @override
  $FooTableTable createAlias(String alias) {
    return $FooTableTable(_db, alias);
  }
}
核心疑问

项目中的列定义为Column<String> get id => text()(),但自动生成的列类型为GeneratedColumn<String?> id,是否有方法获取GeneratedColumn<String>(即null safety非空类型)的生成列?

解答

不存在生成非空泛型GeneratedColumn的配置方式,这是框架的刻意设计:

  • GeneratedColumn统一使用可空泛型,是为了覆盖所有SQL查询场景的返回可能:哪怕列在表结构中定义为非空,执行左连接、外连接、聚合查询时,该列的返回值依然可能为null,只有可空泛型能完全适配这类场景,避免空安全运行时错误。
  • 表定义中声明的Column<String>、integer()这类非空列标记,仅作用于两个核心流程:一是插入、更新数据时的完整性校验,框架会强制要求传入对应非空值;二是自动生成的表实体类(比如示例中的FooTableData)中,对应字段会被标记为非空类型,常规单表查询拿到实体后读取字段不需要额外判空。
  • 不要手动修改生成文件把泛型改成非空,否则连接查询场景下大概率触发空指针异常。日常编写查询逻辑时直接用框架内置的表达式、Value封装类操作列即可,不需要额外处理列本身的泛型类型。

内容的提问来源于stack exchange,提问作者Stacky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:27:22