Flutter中如何将列表型TextEditingController输入存入SQLite?
解决列表型TextEditingController的输入值获取与SQLite存储问题
一、获取列表控制器的所有输入值
列表中的每个元素都是TextEditingController实例,直接遍历列表,逐个取出.text属性就能得到所有输入值。为了避免存入无效的空字符串,建议同时做去空格和非空过滤:
// 获取单个控制器的输入值 final title = titleController.text.trim(); final instructions = _instructionsController.text.trim(); final time = _timeController.text.trim(); final portion = _portionController.text.trim(); // 获取列表控制器的所有输入值(过滤空内容) final ingredients = _ingredientsController .map((controller) => controller.text.trim()) .where((text) => text.isNotEmpty) .toList(); final steps = stepsController .map((controller) => controller.text.trim()) .where((text) => text.isNotEmpty) .toList(); final quantities = _quaController .map((controller) => controller.text.trim()) .where((text) => text.isNotEmpty) .toList();
二、存入SQLite的两种方案
方案1:将列表转为JSON字符串存入单个字段(适合简单场景)
如果数据结构不复杂,不需要单独查询食材、步骤等子项,可以把列表转成JSON字符串,存入SQLite的单个字段中:
import 'package:sqflite/sqflite.dart'; import 'dart:convert'; Future<void> insertRecipe() async { // 打开或创建数据库 final db = await openDatabase('recipes.db'); // 将列表转为JSON字符串 final ingredientsJson = jsonEncode(ingredients); final stepsJson = jsonEncode(steps); final quantitiesJson = jsonEncode(quantities); // 插入主表 await db.insert( 'recipes', { 'title': title, 'instructions': instructions, 'time': time, 'portion': portion, 'ingredients': ingredientsJson, 'steps': stepsJson, 'quantities': quantitiesJson, }, conflictAlgorithm: ConflictAlgorithm.replace, ); }
方案2:使用关联表(规范的数据库设计,适合复杂查询)
如果需要单独查询食材、步骤等数据,建议使用主表+子表的关联结构,通过外键关联主表ID:
1. 创建关联表
Future<void> createTables(Database db) async { // 主表:存储菜谱基本信息 await db.execute(''' CREATE TABLE recipes( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, instructions TEXT, time TEXT, portion TEXT ) '''); // 子表:存储食材信息,通过recipe_id关联主表 await db.execute(''' CREATE TABLE ingredients( id INTEGER PRIMARY KEY AUTOINCREMENT, recipe_id INTEGER NOT NULL, name TEXT NOT NULL, quantity TEXT, FOREIGN KEY (recipe_id) REFERENCES recipes(id) ON DELETE CASCADE ) '''); // 子表:存储步骤信息,通过recipe_id关联主表 await db.execute(''' CREATE TABLE steps( id INTEGER PRIMARY KEY AUTOINCREMENT, recipe_id INTEGER NOT NULL, content TEXT NOT NULL, FOREIGN KEY (recipe_id) REFERENCES recipes(id) ON DELETE CASCADE ) '''); }
2. 插入关联数据(使用事务保证一致性)
Future<void> insertRecipeWithRelations() async { final db = await openDatabase('recipes.db'); // 开启事务,确保主表和子表数据同时插入成功或失败 await db.transaction((txn) async { // 插入主表,返回生成的菜谱ID final recipeId = await txn.insert( 'recipes', { 'title': title, 'instructions': instructions, 'time': time, 'portion': portion, }, ); // 批量插入食材数据(假设ingredients和quantities是一一对应的) for (int i = 0; i < ingredients.length; i++) { await txn.insert( 'ingredients', { 'recipe_id': recipeId, 'name': ingredients[i], 'quantity': quantities[i], }, ); } // 批量插入步骤数据 for (final stepContent in steps) { await txn.insert( 'steps', { 'recipe_id': recipeId, 'content': stepContent, }, ); } }); }
三、关键注意事项
动态创建的TextEditingController列表必须在组件销毁时逐个释放,避免内存泄漏:
@override void dispose() { // 释放单个控制器 titleController.dispose(); _instructionsController.dispose(); _timeController.dispose(); _portionController.dispose(); // 遍历释放列表中的所有控制器 for (final controller in _ingredientsController) { controller.dispose(); } for (final controller in stepsController) { controller.dispose(); } for (final controller in _quaController) { controller.dispose(); } super.dispose(); }
内容的提问来源于stack exchange,提问作者Edgar
相关产品推荐
相关产品推荐

