Whenever I am adding a new row to my database in my flutter app, I am getting this error :
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.
I read different articles and deduced that I may have been calling the constructor more than once, but still not figuring out the way out of it.
Here are some code snippets for the initial reference:
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, ); }, ), ) ], ); } }
Although I am getting my Output fine and the app seems working, It is giving me an error in the debug console every time on hot-restarting :
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)
So, I want to get rid of both these errors so that I can start integrating my APIs
Thanks in advance!
Advertisement
Answer
You should not call AppDatabase()
more than once in your application. Calling AppDatabase()
creates a new instance every time and you end up with many instances of the database. The best way to do this is to create it once and provide it to the needed components. Also, check the Singleton pattern in Dart.