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); } }
错误原因分析
- 缺少数据库版本参数:sqflite明确规定,当
openDatabase方法传入onCreate回调时,必须同时指定version参数。若未设置版本号,onCreate必须为null,否则会触发参数合法性错误。 - 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
相关产品推荐
相关产品推荐

