在 database/storage dropping/deleting table 之后未调用 Sqlite onCreate
Sqlite onCreate isn't invoked after dropping/deleting the table from the database/storage
最小可重现代码:
class Helper {
Database _db;
Future<Database> initDb() async {
if (_db == null) {
final directory = await getApplicationDocumentsDirectory();
_db = await openDatabase(join(directory.path, 'foo.db'), version: 1, onCreate: _onCreate);
}
return _db;
}
Future<void> _onCreate(Database db, _) async {
print('onCreate');
await db.transaction((txn) async {
await txn.execute('CREATE TABLE tableName(abc TEXT)');
});
}
}
这是我的主要方法:
void main() async {
final directory = await getApplicationDocumentsDirectory();
final file = File(join(directory.path, 'foo.db'));
if (await file.exists()) {
await file.delete();
}
// If there had been a file, it's deleted now.
final helper = Helper();
await helper.initDb(); // This must fire `onCreate` but it doesn't.
}
每次 运行 main
方法时,它应该执行 Helper
class 中的 onCreate
方法,但它只执行一次。我在这里做错了什么?
这是默认行为,因为创建数据库时会执行 onCreate 方法。由于数据库是在没有再次执行之前创建的。
如果您打算清除 table 的行,请使用 TRUNCATE 命令。有关更多信息,请查看 link 比较 drop table 和 truncate table here
onCreate
只有在没有数据库文件时才会执行。不是当数据库中没有 table 时。如果您删除数据库文件,那么将在控制台中打印一条消息 onCreate
。这是一个例子:
void main() async {
final directory = await getApplicationDocumentsDirectory();
final path = join(directory.path, 'foo.db');
await File(path).delete();
final helper = Helper();
await helper.initDb();
// await helper.dropTable();
}
此代码每隔 运行 程序打印一条日志消息。
这不是 Sqflite 的工作方式。
第一次创建数据库时,您会为其指定一个版本号。在你的情况下,版本是 1.
Sqflite 将检查设备上是否存在数据库如果存在,它会检查设备上数据库的版本号和代码的版本号,如果版本不相同,如果新版本大于旧版本,它将调用 onUpgrade数据库版本。如果旧版本大于新版本,则降级。不会调用 OnCreate。 onCreate 仅在用户第一次安装您的应用程序时被调用。即使您之后放弃 tables。如果您将来需要在生产应用程序上更新数据库,则必须编写 onUpgrade 方法,在该方法中您必须显式删除 tables 并自己调用 onCreate。并升级数据库版本。
见以下代码。每当您需要 dropAll tables 和 createAgain.
时,使用此代码设置并将版本更改为更高的版本号
如果您不想使用这些版本并明确删除 tables 并重新创建它们。删除 table.
后,您必须自己调用 _onCreate
class Helper {
Database _db;
Future<Database> initDb() async {
if (_db == null) {
final directory = await getDatabasesPath();
final path = join(directory, 'foo.db');
_db = await openDatabase(
path,
version: 2, //+1 to this number whenever you want to update
onCreate: _onCreate,
onUpgrade: _onUpgrade,
);
}
return _db;
}
Future<void> _onUpgrade(
Database db, int previousVersion, int newVersion) async {
_db = db;
await dropTable();
await _onCreate(db, newVersion);
}
Future<void> _onCreate(Database db, int version) async {
print('onCreate');
await db.transaction((txn) async {
await txn.execute('CREATE TABLE tableName(abc TEXT)');
});
}
Future<void> dropTable() async {
await _db.transaction((txn) async {
await txn.execute('DROP TABLE IF EXISTS tableName');
});
}
问题描述从一开始就变了,很难在评论中做出正确的解释,所以这里又是一个答案。
所有现有的响应仍然有效,但问题现在正在转移到类似 删除数据库后未调用 onCreate 的问题。
Every time you run the main method, it should execute the onCreate method in Helper class but it only does that once. What am I doing wrong here?
您并没有具体说明如何 运行(即您之前是否停止过应用程序),所以我假设您只是按下 [=35= 上的 运行 按钮] 执行热重启。
虽然您可能倾向于简单地删除文件,但是您应该使用
deleteDatabase
正确删除数据库。
// Do not call File.delete, it will not work in a hot restart scenario
await File(path).delete();
// Instead do
await deleteDatabase(path);
- 它将正确关闭任何现有的数据库连接
- 它将正确处理将
SQLite
置于
奇怪的状态(基本上 'dart' 一方认为数据库已关闭,而
数据库实际上是在本机端打开的)
如果您调用 File.delete
,虽然您可能认为它有效(即文件不
存在),因为在热重启场景中数据库可能仍处于打开状态
下一次打开将重新使用打开的连接,并且在某个时候会被写入
使用旧数据,下次打开时不会调用 onCreate
数据库。
最小可重现代码:
class Helper {
Database _db;
Future<Database> initDb() async {
if (_db == null) {
final directory = await getApplicationDocumentsDirectory();
_db = await openDatabase(join(directory.path, 'foo.db'), version: 1, onCreate: _onCreate);
}
return _db;
}
Future<void> _onCreate(Database db, _) async {
print('onCreate');
await db.transaction((txn) async {
await txn.execute('CREATE TABLE tableName(abc TEXT)');
});
}
}
这是我的主要方法:
void main() async {
final directory = await getApplicationDocumentsDirectory();
final file = File(join(directory.path, 'foo.db'));
if (await file.exists()) {
await file.delete();
}
// If there had been a file, it's deleted now.
final helper = Helper();
await helper.initDb(); // This must fire `onCreate` but it doesn't.
}
每次 运行 main
方法时,它应该执行 Helper
class 中的 onCreate
方法,但它只执行一次。我在这里做错了什么?
这是默认行为,因为创建数据库时会执行 onCreate 方法。由于数据库是在没有再次执行之前创建的。
如果您打算清除 table 的行,请使用 TRUNCATE 命令。有关更多信息,请查看 link 比较 drop table 和 truncate table here
onCreate
只有在没有数据库文件时才会执行。不是当数据库中没有 table 时。如果您删除数据库文件,那么将在控制台中打印一条消息 onCreate
。这是一个例子:
void main() async {
final directory = await getApplicationDocumentsDirectory();
final path = join(directory.path, 'foo.db');
await File(path).delete();
final helper = Helper();
await helper.initDb();
// await helper.dropTable();
}
此代码每隔 运行 程序打印一条日志消息。
这不是 Sqflite 的工作方式。
第一次创建数据库时,您会为其指定一个版本号。在你的情况下,版本是 1.
Sqflite 将检查设备上是否存在数据库如果存在,它会检查设备上数据库的版本号和代码的版本号,如果版本不相同,如果新版本大于旧版本,它将调用 onUpgrade数据库版本。如果旧版本大于新版本,则降级。不会调用 OnCreate。 onCreate 仅在用户第一次安装您的应用程序时被调用。即使您之后放弃 tables。如果您将来需要在生产应用程序上更新数据库,则必须编写 onUpgrade 方法,在该方法中您必须显式删除 tables 并自己调用 onCreate。并升级数据库版本。
见以下代码。每当您需要 dropAll tables 和 createAgain.
时,使用此代码设置并将版本更改为更高的版本号如果您不想使用这些版本并明确删除 tables 并重新创建它们。删除 table.
后,您必须自己调用 _onCreateclass Helper {
Database _db;
Future<Database> initDb() async {
if (_db == null) {
final directory = await getDatabasesPath();
final path = join(directory, 'foo.db');
_db = await openDatabase(
path,
version: 2, //+1 to this number whenever you want to update
onCreate: _onCreate,
onUpgrade: _onUpgrade,
);
}
return _db;
}
Future<void> _onUpgrade(
Database db, int previousVersion, int newVersion) async {
_db = db;
await dropTable();
await _onCreate(db, newVersion);
}
Future<void> _onCreate(Database db, int version) async {
print('onCreate');
await db.transaction((txn) async {
await txn.execute('CREATE TABLE tableName(abc TEXT)');
});
}
Future<void> dropTable() async {
await _db.transaction((txn) async {
await txn.execute('DROP TABLE IF EXISTS tableName');
});
}
问题描述从一开始就变了,很难在评论中做出正确的解释,所以这里又是一个答案。
所有现有的响应仍然有效,但问题现在正在转移到类似 删除数据库后未调用 onCreate 的问题。
Every time you run the main method, it should execute the onCreate method in Helper class but it only does that once. What am I doing wrong here?
您并没有具体说明如何 运行(即您之前是否停止过应用程序),所以我假设您只是按下 [=35= 上的 运行 按钮] 执行热重启。
虽然您可能倾向于简单地删除文件,但是您应该使用
deleteDatabase
正确删除数据库。
// Do not call File.delete, it will not work in a hot restart scenario
await File(path).delete();
// Instead do
await deleteDatabase(path);
- 它将正确关闭任何现有的数据库连接
- 它将正确处理将
SQLite
置于 奇怪的状态(基本上 'dart' 一方认为数据库已关闭,而 数据库实际上是在本机端打开的)
如果您调用 File.delete
,虽然您可能认为它有效(即文件不
存在),因为在热重启场景中数据库可能仍处于打开状态
下一次打开将重新使用打开的连接,并且在某个时候会被写入
使用旧数据,下次打开时不会调用 onCreate
数据库。