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

Flutter sqflite报错:未指定version时onCreate需为null的技术咨询

问题描述

ArgumentError (Invalid argument(s): onCreate must be null if no version is specified)

在使用sqflite开发Flutter项目的DBmanager数据库管理类时,执行borrarTabla方法触发上述错误,相关代码如下:

import 'package:apptour/basededatos/Empresa.dart';
import 'package:apptour/basededatos/Foto.dart';
import 'package:apptour/basededatos/Lugar.dart';
import 'package:apptour/basededatos/Ruta.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';
import 'dart:io' as io;
import 'package:sqflite/sqflite.dart';

class DBmanager {
  // BASE

  static Future<Database> _openDb() async {
    return openDatabase(join(await getDatabasesPath(), 'apptuor'),
        onCreate: (db, version) {
      return db.execute(
          "CREATE TABLE ruta(id INTEGER, nombre TEXT, urlfoto TEXT"
          "CREATE TABLE empresa(id INTEGER, razonsocial TEXT, descripcion TEXT, urllogo TEXT, ruta_id INTEGER, user_id INTEGER)"
          "CREATE TABLE lugar(id INTEGER, nombre TEXT, descripcion TEXT, urlfoto TEXT, latitud TEXT, longitud TEXT, ruta_id INTEGER)"
          "CREATE TABLE foto(id INTEGER, nombre TEXT, urlfoto TEXT, tipo INTEGER, lugar_id INTEGER)");
    });
  }

// métodos
// rutas
  Future<int> insertarRuta(Ruta modelo) async {
    var bd = await _openDb();

    return await bd.insert("ruta", modelo.toMap());
  }

  Future<List<Ruta>> obtenerRutas(String condicion) async {
    var basededatos = await _openDb();
    List<Map> lista =
        await basededatos.rawQuery("SELECT * FROM ruta WHERE " + condicion);
    List<Ruta> rutas = [];
    for (int i = 0; i < lista.length; i++) {
      rutas.add(
          new Ruta(lista[i]['id'], lista[i]['nombre'], lista[i]['urlfoto']));
    }
    return rutas;
  }

// EMPRESA
  Future<int> insertarEmpresa(Empresa empresa) async {
    var basedetados = await _openDb();
    int respuesta = await basedetados.insert("empresa", empresa.toMap());
    return respuesta;
  }

  Future<List<Empresa>> obtenerEmpresas(String condicion) async {
    var basededatos = await _openDb();
    List<Map> lista =
        await basededatos.rawQuery("SELECT * FROM empresa WHERE " + condicion);
    List<Empresa> empresas = [];
    for (int i = 0; i < lista.length; i++) {
      empresas.add(new Empresa(
        lista[i]['id'],
        lista[i]['razonsocial'],
        lista[i]['descripcion'],
        lista[i]['urllogo'],
        lista[i]['ruta_id'],
        lista[i]['user_id'],
      ));
    }
    return empresas;
  }

  Future<int> actualizarEmpresa(Empresa empresa) async {
    var base = await _openDb();
    return await base.update("empresa", empresa.toMap(),
        where: 'id= ?', whereArgs: [empresa.id]);
  }

  Future<int> borrarTablaId(tabla, id) async {
    var base = await _openDb();
    return await base.delete(tabla, where: 'id= ?', whereArgs: [id]);
  }

  // LUGAR
  Future<int> insertarLugar(Lugar lugar) async {
    var base = await _openDb();
    int respuesta = await base.insert("lugar", lugar.toMap());
    return respuesta;
  }

  Future<List<Lugar>> obtenerLugares(String condicion) async {
    var base = await _openDb();
    List<Map> lista =
        await base.rawQuery("SELECT * FROM lugar WHERE " + condicion);
    List<Lugar> lugares = [];
    for (int i = 0; i < lista.length; i++) {
      lugares.add(new Lugar(
          lista[i]['id'],
          lista[i]['nombre'],
          lista[i]['descripcion'],
          lista[i]['urlfoto'],
          lista[i]['latitud'],
          lista[i]['longitud'],
          lista[i]['ruta_id']));
    }
    return lugares;
  }

  // FOTOS
  Future<int> insertarFoto(Foto foto) async {
    var base = await _openDb();
    int respuesta = await base.insert("foto", foto.toMap());
    return respuesta;
  }

  Future<List<Foto>> obtenerFotos(String condicion) async {
    var base = await _openDb();
    List<Map> lista =
        await base.rawQuery("SELECT * FROM foto WHERE " + condicion);
    List<Foto> fotos = [];
    for (int i = 0; i < lista.length; i++) {
      fotos.add(new Foto(lista[i]['id'], lista[i]['nombre'],
          lista[i]['urlfoto'], lista[i]['tipo'], lista[i]['lugar_id']));
    }
    return fotos;
  }

  // delete
  Future<int> borrarTabla(String tabla) async {
      var base = await _openDb();
      return await base.rawDelete("DELETE FROM " + tabla);
    
  }
}
错误原因分析
  1. 缺少数据库版本参数:sqflite明确规定,当openDatabase方法传入onCreate回调时,必须同时指定version参数。若未设置版本号,onCreate必须为null,否则会触发参数合法性错误。
  2. SQL语法错误:onCreate中的建表语句存在两处问题:
    • 第一个表ruta的创建语句未闭合(缺少))
    • 所有建表语句之间未用分号;分隔,会导致数据库执行SQL时解析失败。
解决方案

1. 修复_openDb方法,补充版本参数并修正SQL语句

修改后的_openDb代码如下:

static Future<Database> _openDb() async {
  return openDatabase(
    join(await getDatabasesPath(), 'apptuor'),
    version: 1, // 必须指定版本号,与onCreate配合使用
    onCreate: (db, version) async {
      // 拆分多个建表语句,用分号分隔确保语法正确
      await db.execute(
        "CREATE TABLE ruta(id INTEGER, nombre TEXT, urlfoto TEXT);"
        "CREATE TABLE empresa(id INTEGER, razonsocial TEXT, descripcion TEXT, urllogo TEXT, ruta_id INTEGER, user_id INTEGER);"
        "CREATE TABLE lugar(id INTEGER, nombre TEXT, descripcion TEXT, urlfoto TEXT, latitud TEXT, longitud TEXT, ruta_id INTEGER);"
        "CREATE TABLE foto(id INTEGER, nombre TEXT, urlfoto TEXT, tipo INTEGER, lugar_id INTEGER);"
      );
    },
  );
}

若担心拼接SQL出错,可改为分别执行每个建表语句:

static Future<Database> _openDb() async {
  return openDatabase(
    join(await getDatabasesPath(), 'apptuor'),
    version: 1,
    onCreate: (db, version) async {
      await db.execute("CREATE TABLE ruta(id INTEGER, nombre TEXT, urlfoto TEXT);");
      await db.execute("CREATE TABLE empresa(id INTEGER, razonsocial TEXT, descripcion TEXT, urllogo TEXT, ruta_id INTEGER, user_id INTEGER);");
      await db.execute("CREATE TABLE lugar(id INTEGER, nombre TEXT, descripcion TEXT, urlfoto TEXT, latitud TEXT, longitud TEXT, ruta_id INTEGER);");
      await db.execute("CREATE TABLE foto(id INTEGER, nombre TEXT, urlfoto TEXT, tipo INTEGER, lugar_id INTEGER);");
    },
  );
}

2. 优化数据库连接管理(可选但推荐)

当前代码每次操作都调用_openDb(),虽sqflite内部会复用连接,但建议改为单例模式管理数据库实例,避免重复初始化:

class DBmanager {
  static Database? _database;

  static Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _openDb();
    return _database!;
  }

  static Future<Database> _openDb() async {
    // 此处使用修复后的_openDb代码
  }

  // 后续所有数据库操作替换为调用DBmanager.database
  Future<int> insertarRuta(Ruta modelo) async {
    var bd = await DBmanager.database;
    return await bd.insert("ruta", modelo.toMap());
  }

  // 其他方法同理修改...
}

内容的提问来源于stack exchange,提问作者Jesus Agustin Candela Moreira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 01:10:29