일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- intent
- Compose
- 안드로이드
- activity
- livedata
- scroll
- 앱바
- Button
- tabbar
- Kotlin
- TEST
- 테스트
- Coroutines
- data
- CustomScrollView
- viewmodel
- Dialog
- DART
- textview
- android
- textfield
- LifeCycle
- binding
- Flutter
- appbar
- ScrollView
- 앱
- drift
- Navigation
- 계측
- Today
- Total
Study Record
[Flutter] drift 시작하기 (Sql 기반 데이터베이스와 테이블 만들기) 본문
✍ drift
드리프트(Drift)는 Flutter 와 dart 를 위한 반응형 지속성 라이브러리로, sqlite 위에 구축되었다. SQL 와 Dart 언어를 사용하여 쿼리를 작성할 수 있고 여러 테이블과 join 연산뿐 아니라 WITH,WINDOW 와 같은 복잡한 SQL 언어도 사용할 수 있다. Android 와 IOS 뿐만 아니라 Windows, Linux, Web 에서도 작동한다. 이 글에서 설명하는 drift 는 2.6.0 버전에 해당한다. 이 글에 해당하는 모든 코드는 dift docs 를 참고했다.
😶 drift 프로젝트에 적용하기
pubspec.yaml 파일에 dependency 를 추가한 뒤, pub get 버튼을 누른다.
dependencies:
drift: ^2.6.0
sqlite3_flutter_libs: ^0.5.0
path_provider: ^2.0.0
path: ^1.8.3
dev_dependencies:
drift_dev: ^2.6.0
build_runner: ^2.3.3
만약, pub get 버튼을 눌렀을 때 version solving failed 과 관련된 에러가 나온다면 path 라이브러리가 1.8.3 과 1.8.2 로 겹쳐 어떤 것을 사용할지 몰라 나오는 오류이므로 dependency_overrides 키워드를 사용하여 해결할 수 있다.
dependency_overrides 로 path 어떤 버전의 라이브러리를 사용할지 정해준다.
dependencies:
drift: ^2.6.0
sqlite3_flutter_libs: ^0.5.0
path_provider: ^2.0.0
path: ^1.8.3
dev_dependencies:
drift_dev: ^2.6.0
build_runner: ^2.3.3
dependency_overrides:
path: ^1.8.3
😶 drift 를 사용하여 데이터베이스와 테이블 생성하기
Todo 테이블과 Category 테이블이 있는 Test_database 데이터베이스를 생성하려고 한다.
😶 테이블 정의하기
먼저 파일이름을 test_database.dart 으로 파일을 생성한 뒤, 테이블을 생성하는 코드이다.
import 'package:drift/drift.dart';
// this will generate a table called "todos" for us. The rows of that table will
// be represented by a class called "Todo".
class Todos extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().withLength(min: 6, max: 32)();
TextColumn get content => text().named('body')();
IntColumn get category => integer().nullable()();
}
// This will make drift generate a class called "Category" to represent a row in
// this table. By default, "Categorie" would have been used because it only
//strips away the trailing "s" in the table name.
@DataClassName('Category')
class Categories extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get description => text()();
}
Table 을 상속받는 Todos, Categories 클래스는 테이블에 해당한다. 나중에 데이터 클래스가 만들어질 때, s 를 뗀 Todo, Categorie 를 사용하게 되는데 DataClassName 어노테이션은 데이터 클래스의 이름을 Categorie 이 아니라 Category 로 사용할 수 있게 해준다. column 은 꼭 "=>" 연산자를 사용해야 하며, 위의 예시처럼 IntColumn, TextColumn 등의 데이터 타입은 Column 으로 설정할 수 있다. Todo 테이블의 content 칼럼은 named('body') 함수에 의해 이름이 content 가 아니라 body 로 사용된다.
😶 데이터베이스 생성하기
part 명령어로 현재 파일 이름의 ".g.dart" 가 붙은 파일을 불러오는데 처음에는 파일이 존재하지 않아 오류가 나오지만 나중에 자동으로 생성될 파일이므로 괜찮다. 파일 이름이 "test_database.dart" 이므로 "test_database.g.dart" 파일을 part 한다. @DriftDatabase 어노테이션에 정의한 테이블 클래스를 넣고 자기 이름 앞에 "_$" 를 상속받는 클래스로 데이터베이스 클래스를 선언한다. 자기 이름 앞에 "_$" 가 붙은 클래스는 "test_database.g.dart" 에 포함된 파일로 나중에 자연스레 오류가 없어진다.
_openConnecton() 함수에서는 기기에 저장된 데이터베이스 정보가 저장된 파일을 불러오는데 없으면 새로 생성된다.
import 'package:drift/drift.dart';
import 'dart:io';
import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
// assuming that your file is called filename.dart. This will give an error at
// first, but it's needed for drift to know about the generated code
part 'test_database.g.dart';
@DriftDatabase(tables: [Todos, Categories])
class TestDatabase extends _$TestDatabase {
// we tell the database where to store the data with this constructor
TestDatabase() : super(_openConnection());
// you should bump this number whenever you change or add a table definition.
// Migrations are covered later in the documentation.
@override
int get schemaVersion => 1;
}
LazyDatabase _openConnection() {
// the LazyDatabase util lets us find the right location for the file async.
return LazyDatabase(() async {
// put the database file, called test_database.sqlite here, into the documents folder
// for your app.
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'test_database.sqlite'));
return NativeDatabase.createInBackground(file);
});
}
😶 빌드하기
위에서 설명한 테이블과 데이터베이스를 생성하는 코드를 합친 "test_database.dart" 파일의 코드이다.
import 'package:drift/drift.dart';
import 'dart:io';
import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
part 'test_database.g.dart';
class Todos extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().withLength(min: 6, max: 32)();
TextColumn get content => text().named('body')();
IntColumn get category => integer().nullable()();
}
@DataClassName('Category')
class Categories extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get description => text()();
}
@DriftDatabase(tables: [Todos, Categories])
class TestDatabase extends _$TestDatabase {
TestDatabase() : super(_openConnection());
@override
int get schemaVersion => 1;
}
LazyDatabase _openConnection() {
return LazyDatabase(() async {
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'test_database.sqlite'));
return NativeDatabase.createInBackground(file);
});
}
터미널에서 "flutter pub run build_runner build" 를 실행하면 문제가 없다면 test_database.g.dart 파일이 생성될 것이다. 그러면 test_database.dart 파일에서의 오류도 전부 사라진다.
> flutter pub run build_runner build
😶 main 에서 테스트하기
main 함수가 포함된 파일로 돌아와 test_database.dart 파일에 만들어둔 데이터베이스 클래스(TestDatabase) 를 가져와 insert 명령어로 테스트해본다. 테스트를 위해 작성하는 코드이기 때문에 runApp() 함수를 실행하기 전(앱이 초기화되기 전)에 드리프트(drift)를 사용하는 것이기 때문에 WidgetsFlutterBinding.ensureInitialized(); 함수를 미리 실행해 준다.
import 'package:drift/drift.dart' show Value;
import 'package:drift_test/database/test_database.dart';
import 'package:flutter/material.dart';
void main() async {
// runApp 이 실행하면 자동으로 실행되지만 플러터 프로그램이 준비가 됐는지 확인
WidgetsFlutterBinding.ensureInitialized();
final database = TestDatabase();
// Simple insert:
await database
.into(database.categories)
.insert(CategoriesCompanion.insert(description: Value('my first category')));
// Simple select:
final allCategories = await database.select(database.categories).get();
print('Categories in database: $allCategories');
// 앱 실행
runApp(const MyApp());
}
...
데이터베이스가 잘 생성되었다면 Log 에 Categories in database ~ 가 출력되었을 것이다.
안드로이드의 경우, Device File Explorer 로 확인 결과 test_database.sqlite 가 app_flutter 파일 안에 생성된다.
DB Brower 프로그램으로 Device File Explorer 에서 찾은 파일을 열어보니 위에서 선언한 대로 테이블이 잘 생성되었다.
'Flutter > 라이브러리' 카테고리의 다른 글
[Flutter] 간단한 데이터 저장 (flutter_secure_storage) (0) | 2023.04.07 |
---|---|
[Flutter] drift 에서 Future 와 Stream 차이점 (2) | 2023.03.26 |
[Flutter] 데이터베이스 importing (drift) (0) | 2023.03.26 |
[Flutter] drift 에서 테이블 데이터 가져오기 (insert, select, delete, update etc) (0) | 2023.03.25 |
[Flutter] 데이터베이스 table 만들기 (drift) (0) | 2023.03.24 |