Frequently asked questions
Using the database¶
If you've created a MyDatabase
class by following the getting started guide, you
still need to somehow obtain an instance of it. It's recommended to only have one (singleton) instance of your database,
so you could store that instance in a global variable:
Vanilla flutter¶
It would be cleaner to useInheritedWidgets
for that, and the provider
package helps here:
Provider¶
If you're using the provider package, you can wrap your top-level widget in a provider that manages the database instance:
void main() {
runApp(
Provider<MyDatabase>(
create: (context) => MyDatabase(),
child: MyFlutterApp(),
dispose: (context, db) => db.close(),
),
);
}
Provider.of<MyDatabase>(context)
.
GetX¶
If you're using the GetX package, you can add it as a service that manages the database instance:.
Your widgets would then have access to the database usingGet.find<MyDatabase>().your_method
.
A more complex architecture¶
If you're strict on keeping your business logic out of the widget layer, you probably use some dependency injection
framework like kiwi
or get_it
to instantiate services and view models. Creating a singleton instance of MyDatabase
in your favorite dependency injection framework for flutter hence solves this problem for you.
Why am I getting no such table errors?¶
If you add another table after your app has already been installed, you need to write a migration that covers creating that table. If you're in the process of developing your app and want to use un- and reinstall your app instead of writing migrations, that's fine too. Please note that your apps data might be backed up on Android, so manually deleting your app's data instead of a reinstall is necessary on some devices.
How do I fix lints in generated files?¶
Based on your linter settings, you might see some warnings in the .g.dart
files generated by drift. Since lints are mainly used for
human-written code, we recommend to disable static analysis on generated files. For that, generate a top-level file called
analysis_options.yaml
in your project and add this content:
You might have to restart your IDE for the changes to apply.
How can I inspect generated SQL?¶
All database implementations (NativeDatabase
, FlutterQueryExecutor
, ...) have a logStatements
parameter that
you can set to true
. When enabled, drift will print the statements it runs.
How do I insert data on the first app start?¶
You can populate the database on the first start of your app with a custom migration strategy. To insert data when the database is created (which usually happens when the app is first run), you can use this:
MigrationStrategy(
onCreate: (m) async {
await m.createAll(); // create all tables
await into(myTable).insert(...); // insert on first run.
}
)
You can even use transactions or batches in the onCreate
callback.
Another approach is to include a pre-populated database in your app's asset and use that one:
QueryExecutor databaseWithDefaultAsset(File file, String asset) {
// A LazyDatabase lets us do async initialization work.
return LazyDatabase(() async {
if (!await file.exists()) {
// Database does not exist yet, use default from asset
final content = await rootBundle.load(asset);
await file.parent.create(recursive: true);
await file.writeAsBytes(content.buffer.asUint8List(0));
}
});
}
My generated code is using another class with the same name¶
When you have an imported a class with the same name as the should-be generated
ones on your database.dart
file and your run build_runner
there is a known
problem about it using the imported class instead of the generated ones.
To solve that, if you can, you can enable
modular code generation.
It slightly changes how drift is used, but you probably will only have to update
a few files to change parts to imports. The big difference is that it allows drift
to emit a standalone library file instead of a part - that can have its own imports,
so this is much easier and we'll use the correct imports even when the same name
classes are imported in your database.dart
file.
How does drift compare to X?¶
There are a variety of good persistence libraries for Dart and Flutter.
That said, here's an incomplete (and obviously biased) list of great libraries and how drift compares to them. If you have experience with any of these (or other) libraries and want to share how they compare to drift, please feel invited to contribute to this page.
sqflite, sqlite3¶
Sqflite is a Flutter package that provides bindings to the sqlite api for both iOS and Android. It's well maintained
and has stable api. In fact, the moor_flutter
or drift_sqflite
variants are built on top of sqflite. But even though sqflite
has an api to construct some simple queries in Dart, drift goes a bit further by
- Generating type-safe mapping code for your queries
- Providing auto-updating streams for queries
- Managing
CREATE TABLE
statements and most schema migrations - A more fluent api to compose queries
Still, for most apps that don't need these features, sqflite can be a very fitting persistence library.
The same thing applies to the sqlite3
package - package:drift/native.dart
uses that library, but provides
additional services on top.
sqlcool¶
Sqlcool is a lightweight library around sqflite that makes writing queries and schema management easier, it also has auto-updating streams. It can be a decent alternative to drift if you don't want/need generated code to parse the result of your queries.
floor¶
Floor also has a lot of convenience features like auto-updating queries and schema migrations. Similar to drift, you define the structure of your database in Dart. Then, you have write queries in sql - the mapping code if generated by floor. Drift has a similar feature, but it can also verify that your queries are valid at compile time. Drift additionally has an api that lets you write some queries in Dart instead of sql.
A difference between these two is that Floor lets you write your own classes and generates mapping code around that. By default, drift generates most classes for you, which can make it easier to use, but makes the api less flexible in some instances. Drift can also be used with custom row classes though.
firebase¶
Both the Realtime Database and Cloud Datastore are easy to use persistence libraries that can sync across devices while still working offline. Both of them feature auto-updating streams and a simple query api. However, neither of them is a relational database, so they don't support useful sql features like aggregate functions, joins, or complex filters.
Firebase is a very good option when
- your data model can be expressed as documents instead of relations
- you don't have your own backend, but still need to synchronize data
Can I view a drift database?¶
Yes! Drift stores its data in a sqlite3 database file that can be extracted from the device and inspected locally.
To inspect a drift database directly in your app, you can use the drift_db_viewer
package by Koen Van Looveren.
There is also an under-development DevTools Extension that comes when you add drift
to your app. Open DevTools and try it out! Contributions and feedback are definitely welcome!