如何在使用 flutter_moor 时停止多次创建 class 数据库文件?
How to stop class database file getting created multiple times when using flutter_moor?
每当我在 flutter 应用程序中向我的数据库添加新行时,我都会收到此错误:
WARNING (moor): It looks like you've created the database classAppDatabase multiple times. When these two databases use the same QueryExecutor, race conditions will ocur and might corrupt the database.
我阅读了不同的文章并推断出我可能不止一次调用构造函数,但仍然没有找到解决方法。
这里有一些代码片段供初步参考:
pubspec.yaml:
dependencies:
flutter:
sdk: flutter
basic_utils: ^2.6.3
cupertino_icons: ^1.0.0
flutter_blue: ^0.7.3
google_fonts: ^1.1.1
http: ^0.12.2
json_annotation: ^3.1.1
logging: ^0.11.4
#moor: ^3.4.0
moor_flutter: ^3.1.0
provider: ^4.3.3
sqflite: ^1.3.2+3
sqlite3_flutter_libs: ^0.3.0
url_launcher: ^5.7.10
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.9.0
chopper_generator: ^3.0.4
json_serializable: ^3.3.0
moor_generator: ^3.4.1
moor_database.dart:
import 'package:moor_flutter/moor_flutter.dart';
part 'moor_database.g.dart';
@DataClassName('AvailableFunctionTable') //Final Table Name
class AvailableFunctionsTable extends Table {
IntColumn get id => integer()();
TextColumn get make => text().withLength(min: 1, max: 50)();
TextColumn get model => text().withLength(min: 1, max: 50).nullable()();
IntColumn get year => integer().nullable()();
TextColumn get functionType => text().withLength(min: 1, max: 100)();
TextColumn get functionName => text().withLength(min: 1, max: 100)();
@override
Set<Column> get primaryKey => {id};
}
@UseMoor(tables: [AvailableFunctionsTable])
class AppDatabase extends _$AppDatabase {
AppDatabase()
: super(FlutterQueryExecutor.inDatabaseFolder(
path: "db.sqlite", logStatements: true));
int get schemaVersion => 1;
Future<List<AvailableFunctionTable>> getAllAvailableFunctionss() =>
select(availableFunctionsTable).get();
Stream<List<AvailableFunctionTable>> watchAllAvailableFunctionss() =>
select(availableFunctionsTable).watch();
Future insertAvailableFunctions(AvailableFunctionTable availableFunctions) =>
into(availableFunctionsTable).insert(availableFunctions);
Future updateAvailableFunctions(AvailableFunctionTable availableFunctions) =>
update(availableFunctionsTable).replace(availableFunctions);
Future deleteAvailableFunctions(AvailableFunctionTable availableFunctions) =>
delete(availableFunctionsTable).delete(availableFunctions);
}
main.dart:
void main() {
runApp(AvFunctionsScreen());
}
class AvFunctionsScreen extends StatefulWidget {
@override
_AvFunctionsScreenState createState() => _AvFunctionsScreenState();
}
class _AvFunctionsScreenState extends State<AvFunctionsScreen> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
home: Scaffold(
appBar: AppBar(
title: Text("AvFunctionsScreen List"),
),
body: SingleChildScrollView(child: NewEntry()),
),
);
}
}
class NewEntry extends StatefulWidget {
@override
_NewEntryState createState() => _NewEntryState();
}
class _NewEntryState extends State<NewEntry> {
TextEditingController idController = TextEditingController();
TextEditingController makeController = TextEditingController();
TextEditingController modelController = TextEditingController();
TextEditingController functionNameController = TextEditingController();
TextEditingController functionTypeController = TextEditingController();
TextEditingController yearController = TextEditingController();
bool isloading = false;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: 'id'),
keyboardType: TextInputType.number,
controller: idController,
),
TextField(
decoration: InputDecoration(hintText: 'make'),
keyboardType: TextInputType.text,
controller: makeController,
),
TextField(
decoration: InputDecoration(hintText: 'model'),
keyboardType: TextInputType.text,
controller: modelController,
),
TextField(
decoration: InputDecoration(hintText: 'year'),
keyboardType: TextInputType.number,
controller: yearController,
),
TextField(
decoration: InputDecoration(hintText: 'func type'),
keyboardType: TextInputType.text,
controller: functionTypeController,
),
TextField(
decoration: InputDecoration(hintText: 'func name'),
keyboardType: TextInputType.text,
controller: functionNameController,
),
RaisedButton(
onPressed: () {
setState(() {
AppDatabase().insertAvailableFunctions(AvailableFunctionTable(
id: int.parse(idController.text),
make: makeController.text,
model: modelController.text,
year: int.parse(yearController.text),
functionName: functionNameController.text,
functionType: functionTypeController.text,
));
idController.clear();
makeController.clear();
modelController.clear();
yearController.clear();
functionNameController.clear();
functionTypeController.clear();
});
},
color: Colors.green,
child: Text("Add info"),
),
Container(
height: 700,
width: double.infinity,
child: StreamBuilder(
stream: AppDatabase().watchAllAvailableFunctionss(),
builder: (context,
AsyncSnapshot<List<AvailableFunctionTable>> snapshot) {
return ListView.builder(
itemBuilder: (_, index) {
return Card(
color: Colors.blueAccent,
child: ListTile(
leading: CircleAvatar(
child: Text('${index + 1}'),
radius: 20,
),
title: Text(snapshot.data[index].id.toString() +
' ' +
snapshot.data[index].year.toString()),
subtitle: Text(snapshot.data[index].make +
' ' +
snapshot.data[index].model +
' ' +
snapshot.data[index].functionType +
' ' +
snapshot.data[index].functionName),
trailing: IconButton(
icon: Icon(Icons.delete_outline),
onPressed: () {
setState(() {
AppDatabase().deleteAvailableFunctions(
snapshot.data[index]);
});
},
color: Colors.red,
)),
);
},
itemCount: snapshot?.data?.length,
);
},
),
)
],
);
}
}
虽然我的输出正常并且应用程序似乎可以正常工作,但每次热重启时它都会在调试控制台中给我一个错误:
The method '[]' was called on null.
Receiver: null
Tried calling: '' (The actual error has a pair of square brackets followed by a pair of round brackets having a zero between the round brackets instead of quotes)
所以,我想摆脱这两个错误,以便我可以开始集成我的 API
提前致谢!
您不应在应用程序中多次调用 AppDatabase()
。每次调用 AppDatabase()
都会创建一个新实例,最终会得到许多数据库实例。最好的方法是创建一次并提供给需要的组件。另外,检查 Dart 中的 Singleton 模式。
每当我在 flutter 应用程序中向我的数据库添加新行时,我都会收到此错误:
WARNING (moor): It looks like you've created the database classAppDatabase multiple times. When these two databases use the same QueryExecutor, race conditions will ocur and might corrupt the database.
我阅读了不同的文章并推断出我可能不止一次调用构造函数,但仍然没有找到解决方法。
这里有一些代码片段供初步参考:
pubspec.yaml:
dependencies:
flutter:
sdk: flutter
basic_utils: ^2.6.3
cupertino_icons: ^1.0.0
flutter_blue: ^0.7.3
google_fonts: ^1.1.1
http: ^0.12.2
json_annotation: ^3.1.1
logging: ^0.11.4
#moor: ^3.4.0
moor_flutter: ^3.1.0
provider: ^4.3.3
sqflite: ^1.3.2+3
sqlite3_flutter_libs: ^0.3.0
url_launcher: ^5.7.10
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^1.9.0
chopper_generator: ^3.0.4
json_serializable: ^3.3.0
moor_generator: ^3.4.1
moor_database.dart:
import 'package:moor_flutter/moor_flutter.dart';
part 'moor_database.g.dart';
@DataClassName('AvailableFunctionTable') //Final Table Name
class AvailableFunctionsTable extends Table {
IntColumn get id => integer()();
TextColumn get make => text().withLength(min: 1, max: 50)();
TextColumn get model => text().withLength(min: 1, max: 50).nullable()();
IntColumn get year => integer().nullable()();
TextColumn get functionType => text().withLength(min: 1, max: 100)();
TextColumn get functionName => text().withLength(min: 1, max: 100)();
@override
Set<Column> get primaryKey => {id};
}
@UseMoor(tables: [AvailableFunctionsTable])
class AppDatabase extends _$AppDatabase {
AppDatabase()
: super(FlutterQueryExecutor.inDatabaseFolder(
path: "db.sqlite", logStatements: true));
int get schemaVersion => 1;
Future<List<AvailableFunctionTable>> getAllAvailableFunctionss() =>
select(availableFunctionsTable).get();
Stream<List<AvailableFunctionTable>> watchAllAvailableFunctionss() =>
select(availableFunctionsTable).watch();
Future insertAvailableFunctions(AvailableFunctionTable availableFunctions) =>
into(availableFunctionsTable).insert(availableFunctions);
Future updateAvailableFunctions(AvailableFunctionTable availableFunctions) =>
update(availableFunctionsTable).replace(availableFunctions);
Future deleteAvailableFunctions(AvailableFunctionTable availableFunctions) =>
delete(availableFunctionsTable).delete(availableFunctions);
}
main.dart:
void main() {
runApp(AvFunctionsScreen());
}
class AvFunctionsScreen extends StatefulWidget {
@override
_AvFunctionsScreenState createState() => _AvFunctionsScreenState();
}
class _AvFunctionsScreenState extends State<AvFunctionsScreen> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
home: Scaffold(
appBar: AppBar(
title: Text("AvFunctionsScreen List"),
),
body: SingleChildScrollView(child: NewEntry()),
),
);
}
}
class NewEntry extends StatefulWidget {
@override
_NewEntryState createState() => _NewEntryState();
}
class _NewEntryState extends State<NewEntry> {
TextEditingController idController = TextEditingController();
TextEditingController makeController = TextEditingController();
TextEditingController modelController = TextEditingController();
TextEditingController functionNameController = TextEditingController();
TextEditingController functionTypeController = TextEditingController();
TextEditingController yearController = TextEditingController();
bool isloading = false;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: 'id'),
keyboardType: TextInputType.number,
controller: idController,
),
TextField(
decoration: InputDecoration(hintText: 'make'),
keyboardType: TextInputType.text,
controller: makeController,
),
TextField(
decoration: InputDecoration(hintText: 'model'),
keyboardType: TextInputType.text,
controller: modelController,
),
TextField(
decoration: InputDecoration(hintText: 'year'),
keyboardType: TextInputType.number,
controller: yearController,
),
TextField(
decoration: InputDecoration(hintText: 'func type'),
keyboardType: TextInputType.text,
controller: functionTypeController,
),
TextField(
decoration: InputDecoration(hintText: 'func name'),
keyboardType: TextInputType.text,
controller: functionNameController,
),
RaisedButton(
onPressed: () {
setState(() {
AppDatabase().insertAvailableFunctions(AvailableFunctionTable(
id: int.parse(idController.text),
make: makeController.text,
model: modelController.text,
year: int.parse(yearController.text),
functionName: functionNameController.text,
functionType: functionTypeController.text,
));
idController.clear();
makeController.clear();
modelController.clear();
yearController.clear();
functionNameController.clear();
functionTypeController.clear();
});
},
color: Colors.green,
child: Text("Add info"),
),
Container(
height: 700,
width: double.infinity,
child: StreamBuilder(
stream: AppDatabase().watchAllAvailableFunctionss(),
builder: (context,
AsyncSnapshot<List<AvailableFunctionTable>> snapshot) {
return ListView.builder(
itemBuilder: (_, index) {
return Card(
color: Colors.blueAccent,
child: ListTile(
leading: CircleAvatar(
child: Text('${index + 1}'),
radius: 20,
),
title: Text(snapshot.data[index].id.toString() +
' ' +
snapshot.data[index].year.toString()),
subtitle: Text(snapshot.data[index].make +
' ' +
snapshot.data[index].model +
' ' +
snapshot.data[index].functionType +
' ' +
snapshot.data[index].functionName),
trailing: IconButton(
icon: Icon(Icons.delete_outline),
onPressed: () {
setState(() {
AppDatabase().deleteAvailableFunctions(
snapshot.data[index]);
});
},
color: Colors.red,
)),
);
},
itemCount: snapshot?.data?.length,
);
},
),
)
],
);
}
}
虽然我的输出正常并且应用程序似乎可以正常工作,但每次热重启时它都会在调试控制台中给我一个错误:
The method '[]' was called on null. Receiver: null Tried calling: '' (The actual error has a pair of square brackets followed by a pair of round brackets having a zero between the round brackets instead of quotes)
所以,我想摆脱这两个错误,以便我可以开始集成我的 API
提前致谢!
您不应在应用程序中多次调用 AppDatabase()
。每次调用 AppDatabase()
都会创建一个新实例,最终会得到许多数据库实例。最好的方法是创建一次并提供给需要的组件。另外,检查 Dart 中的 Singleton 模式。