您好,登錄后才能下訂單哦!
這篇“Flutter怎么用ORM框架簡化本地數據庫管理”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Flutter怎么用ORM框架簡化本地數據庫管理”文章吧。
floor
是基于 sqflite
的一個輕量級的 ORM 框架,通過注解和代碼生成可以將數據庫數據直接映射為實體類對象。floor
內置了很多操作數據庫的方法,比如增刪改查,讓我們快速接入數據庫。同時,也可以在注解中編寫 SQL來實現復雜的數據庫查詢,比如 IN
查詢、數據統計等等。通過注解和代碼生成能夠減少大量手寫代碼,提高我們的開發效率和代碼的可維護性。 floor 需要引入的開發依賴如下,都是用于基于注解生成代碼。
dev_dependencies: flutter_test: sdk: flutter # ... floor_generator: ^1.4.1 build_runner: ^2.3.3
接下來我們就以之前的備忘錄為例,來看看使用 floor
后的改善。
我們之前的備忘錄類 Memo
需要自己編寫 fromJson
和 toJson
方法來實現數據庫數據到實體類對象的轉換。此外,遇到 SQLite 不支持的數據類型(如 DateTime
和 List<String>
)時,還需要處理轉換代碼。我們來看 floor
如何處理。 floor
將數據庫操作分為實體類和 DAO,實體類與數據庫的映射通過注解完成。例如我們的 Memo
類,調整后的代碼如下所示。
@entity class Memo { @PrimaryKey(autoGenerate: true) final int? id; String title; String content; @ColumnInfo(name: 'created_time') DateTime createdTime; @ColumnInfo(name: 'modified_time') DateTime modifiedTime; List<String> tags; Memo({ this.id, required this.title, required this.content, required this.createdTime, required this.modifiedTime, required this.tags, }); }
這里說明一下常見的注解:
@entity
:表示這是一個實體類,會和數據庫的某個數據表映射,默認表名就是類名。如果要手動指定表名,可以使用@Entity(tableName: tableName)
通過 tableName
指定數據表名稱。floor 會自動根據@entity
注解生成創建數據表的 SQL 語句。
@primaryKey
:表示字段為主鍵,如果需要使用自增主鍵,可以使用@PrimaryKey(autoGenerate: true)
。
@ColumnInfo(name: name)
:設置實體類成員屬性和數據表字段的映射關系,默認 floor 使用的數據表字段名稱和類成員屬性名稱一致,如果需要指定數據表字段名,就可以使用這個注解。
@ignore
:忽略某個成員屬性,即該屬性不產生相應的數據表字段。注意,通過 get 方法產生的計算屬性默認就會被忽略,例如長方形面積 double get area => width * height
。
DAO 用于從數據庫查詢數據并轉換為實體類對象,從數據庫查詢數據和轉換的代碼通過注解直接生成。DAO 提供了基礎的插入、更新和刪除方法,這些方法可以通過注解@insert
、@update
和@delete
完成,不需要編寫 SQL。 同時,對于插入和更新可以設置沖突策略,策略可以是中止(abort)、回滾(rollback)、替換(replace)、忽略(ignore)、失敗(fail)。其中除了替換以外,其他都是和數據庫事務有關。
@dao abstract class MemoDao { @Query('SELECT * FROM Memo ORDER BY modified_time DESC') Future<List<Memo>> findAllMemos(); @Query( 'SELECT * FROM Memo WHERE title LIKE :searchKey OR content LIKE :searchKey ORDER BY modified_time DESC') Future<List<Memo>> findMemoWithSearchKey(String searchKey); @Query('SELECT * FROM Memo WHERE id = :id') Stream<Memo?> findMemoById(int id); @insert Future<void> insertMemo(Memo memo); @Update(onConflict: OnConflictStrategy.replace) Future<void> updateMemo(Memo memo); @delete Future<void> deleteMemo(Memo memo); }
使用 floor
可以統一 Dart 數據類型到 SQLite 字段的轉換方式。通過定義不同的類型轉換器TypeConverter
實現數據庫和Dart
數據類型的轉換,從而避免了每個實體類都要單獨編寫轉換代碼。比如我們在備忘錄用到了兩個類型 DateTime
和 List<String>
就定義了對應的轉換器。
class StringListConverter extends TypeConverter<List<String>, String> { @override List<String> decode(String databaseValue) { return databaseValue.isNotEmpty ? databaseValue.split('|') : []; } @override String encode(List<String> value) { return value.join('|'); } } class DateTimeConverter extends TypeConverter<DateTime, int> { @override DateTime decode(int databaseValue) { return DateTime.fromMillisecondsSinceEpoch(databaseValue); } @override int encode(DateTime value) { return value.millisecondsSinceEpoch; } }
使用轉換器只需要在定義數據庫FloorDatabase
的抽象類的時候引入到注解@TypeConverters
就可以了。
@TypeConverters([StringListConverter, DateTimeConverter]) @Database(version: 1, entities: [Memo]) abstract class MemoDatabase extends FloorDatabase { MemoDao get memoDao; }
通常來說 DAO 對象會在很多地方共用,適合使用單例方式來構造。這里我們在App啟動的時候就使用 GetIt來實現MemoDao 的單例注冊。
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); final database = await $FloorMemoDatabase.databaseBuilder('app_database.db').build(); final dao = database.memoDao; getIt.registerSingleton<MemoDao>(dao, signalsReady: true); runApp(const MyApp()); }
這里調用ensureInitialized
這個方法是保證 Flutter 和原生交互的部分已經完成,因為在 sqflite 中需要使用原生的文件存儲。 備忘錄列表的代碼改造涉及數據操作的有兩處,分別是列表刷新和刪除備忘錄。列表模糊搜索時需要自己組裝模糊搜索的字符,比如我們這里使用了百分號將搜索關鍵詞包裹實現任意匹配。刪除備忘錄需要根據是否有搜索調用不同的方法,這是因為對應的 SQL 不同。
void _refreshMemoList({String? searchKey}) async { List<Memo> memoList = searchKey == null ? await GetIt.I<MemoDao>().findAllMemos() : await GetIt.I<MemoDao>().findMemoWithSearchKey('%$searchKey%'); setState(() { _memoList = memoList; }); }
刪除就非常簡單了,直接調用刪除方法就好了。
void _deleteMemo(Memo memo) async { final confirmed = await _showDeleteConfirmationDialog(memo); if (confirmed != null && confirmed) { await GetIt.I<MemoDao>().deleteMemo(memo); _refreshMemoList(); if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text('已刪除 "${memo.title}"'), duration: const Duration(seconds: 2), )); } }
添加備忘錄的頁面只需要更改保存備忘錄的方法,而且因為不需要再對時間做轉換,方法更為簡潔。
Future<void> _saveMemo(BuildContext context) async { var memo = Memo( title: _title, content: _content, createdTime: DateTime.now(), modifiedTime: DateTime.now(), tags: _tags); // 保存備忘錄 await GetIt.I<MemoDao>().insertMemo(memo); }
編輯備忘錄頁面也類似,調用 updateMemo
方法即可完成保存。
Future<void> _saveMemo(BuildContext context) async { widget.memo.title = _title; widget.memo.content = _content; widget.memo.modifiedTime = DateTime.now(); // 保存備忘錄 await GetIt.I<MemoDao>().updateMemo(widget.memo); }
代碼已經提交到:本地存儲相關代碼,注意如果更改了 ORM 相關的類,需要運行下面的命令重新生成代碼。
flutter packages pub run build_runner build
可以看到,通過 floor
這樣的 ORM 框架可以讓整個本地數據庫管理的代碼更為簡潔,復用性更高。如果說是本地數據存儲比較復雜的,推薦使用 ORM 框架來管理。
以上就是關于“Flutter怎么用ORM框架簡化本地數據庫管理”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。