Flutter SQLite 사용하기
이번 포스팅에서는 Flutter를 이용하여 내부 데이터베이스를 사용하는 방법에 대하여 알아보겠습니다.
0. 의존성 추가
dependencies:
flutter:
sdk: flutter
sqflite:
path:
시작하기 전에 pubspec.yaml에 위의 내용을 추가해줍니다.
1. 데이터 모델 생성
class MemoItem {
final int id;
final String title;
final String contents;
final bool isSecret;
final bool isImportance;
final String? password;
final int timestamp;
final int colorGroup;
MemoItem(
{this.id = 0,
this.title = "",
this.contents = "",
this.isSecret = false,
this.isImportance = false,
this.password,
this.timestamp = 0,
this.colorGroup = 0}
);
Map<String, dynamic> toMap() {
return {
'title': title,
'contents': contents,
'isSecret': isSecret,
'isImportance': isImportance,
'password': password,
'timestamp': timestamp,
'colorGroup': colorGroup,
};
}
준비작업이 완료되었으면 데이터베이스에서 사용할 모델을 만들어줍니다.
만들고자 하는 테이블에 맞게 클래스를 만들어주시면 됩니다.
toMap()
은 추후에 데이터베이스와 데이터를 주고받을 때 사용하게 됩니다.
주의할 점은 Key값은 테이블의 칼럼명과 동일하게 설정해야 합니다.
2. 데이터베이스 생성 및 테이블 생성
initDB() async {
String path = join(await getDatabasesPath(), "flutter_my_memo.db");
return await openDatabase(path, version: 1, onCreate: (db, version) async {
await db.execute('''
CREATE TABLE MEMO(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
contents TEXT,
isSecret BOOLEAN,
isImportance BOOLEAN,
password TEXT,
timestamp INTEGER,
colorGroup INTEGER
)
''');
});
}
join()
을 통하여 데이터베이스의 경로를 설정합니다.
openDtabase()
를 이용하여 데이터베이스의 정보를 가져오게 됩니다.
onCreate()
를 이용하여 데이터베이스를 최초 실행 시 동작을 수행합니다.
execute()
를 이용하여 데이터베이스에 명령을 줄 수 있고 위의 예제에서는 MEMO 테이블을 생성하였습니다.
Future<Database?> get database async {
_database = await initDB();
return _database;
}
위에서 만든 initDB()를 위와 같이 설정하면 비동기로 데이터베이스를 가져올 수 있습니다.
3. 데이터 추가
static const String memoTableName = "Memo";
Future<void> insert(MemoItem item) async {
final db = await database;
await db!.insert(
memoTableName,
item.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace
);
}
데이터베이스의 기본 함수로 insert()
를 이용하여 데이터를 추가할 수 있습니다.
첫 번째 인자 값으로는 테이블 명을 넣으면 됩니다.
두 번째 인자 값으로는 데이터를 넣어주시면 되는데 Map
형식으로 넣어주어야 하므로 위에서 만든 toMap()
을 이용해 줍니다.
세 번째 인자 값은 선택으로 ConflictAlgorithm
을 넣어주었습니다.
ConflictAlgorithm
는 insert
과정 중 충돌이 발생하였을 때 방법을 설정하는 것으로
rollback
, abort
, fail
, ignore
, replace
중 원하는 것을 선택하면 됩니다.
Future<int> insert(String table, Map<String, Object?> values,
{String? nullColumnHack, ConflictAlgorithm? conflictAlgorithm});
4. 데이터 조회
Future<List<MemoItem>> getMemoList(String keyword) async {
final db = await database;
final List<Map<String, dynamic>> maps = await db!.query(memoTableName,
where: "title LIKE ?",
whereArgs: ['%$keyword%'],
);
return List.generate(maps.length, (i) {
return MemoItem(
id: maps[i]['id'],
title: maps[i]["title"],
contents: maps[i]["contents"],
isSecret: maps[i]["isSecret"] == 1,
isImportance: maps[i]["isImportance"] == 1,
password: maps[i]["password"],
timestamp: maps[i]["timestamp"],
colorGroup: maps[i]["colorGroup"],
);
}
데이터 조회는 데이터베이스의 함수인 query
를 통해 가져올 수 있습니다.
첫 번째인 자는 동일하게 테이블 명을 입력해주면 되고 그 이외는 선택입니다.
위의 예제에서는 타이틀이 특정 문구가 들어가는 메모를 검색하는 방법입니다.
특정 문구의 경우 외부로부터 받아오는 값이므로
where
에는 "title LIKE ?"를 입력해줍니다.
? 에 해당하는 내용을 whereArgs
에서 배열 형태로 값을 입력해줍니다.
만약 입력받아야 할 값이 여러 개인 경우 whrer
에?를 여러 개 입력해주고
whereArgs
에서 순서대로 입력해주면 됩니다.
query
로 받아온 값은 리스트에 담길 때 Map <String, dynmic>
형태로 담기게 됩니다.
이렇게 되면 사용할 때마다 형 변환을 해주어야 하므로 결과값을 리턴하기 전에 형변환을 해줍니다.
List.generate()
를 이용하면 간단하게 하실 수 있습니다.
bool
타입의 경우 데이터베이스에서 리턴을 0과 1로 해준다는 점을 주의해야 합니다.
query
에는 where
외에도 다음과 같은 조건을 추가할 수 있습니다.
Future<List<Map<String, Object?>>> query(String table,
{bool? distinct,
List<String>? columns,
String? where,
List<Object?>? whereArgs,
String? groupBy,
String? having,
String? orderBy,
int? limit,
int? offset});
5. 업데이트
Future<void> updateImportance({required int id, required bool value}) async {
final db = await database;
var result = await db!.update(
memoTableName,
{
'isImportance': value ? 1 : 0,
},
where: "id = ?",
whereArgs: [id]);
}
업데이트는 동일하게 update()
를 이용하면 됩니다.
첫 번째 인자는 역시 테이블 명입니다.
두 번째 인자는 Map
형태로 변경하고자 하는 내용을 넣어주시면 됩니다.
위의 예제에서는 일부만 변경하기 때문에 위와 같이 넣었습니다.
전체 내용을 변경할 때에는 만든 클래스에 데이터를 담은 뒤 toMap()
으로 넣어주시면 됩니다.
그 외는 선택 사항입니다.
Future<int> update(String table, Map<String, Object?> values,
{String? where,
List<Object?>? whereArgs,
ConflictAlgorithm? conflictAlgorithm});
6. 삭제
Future<int> deleteMemo({required int id}) async {
final db = await database;
var result =
await db!.delete(memoTableName, where: "id = ?", whereArgs: [id]);
return result;
}
삭제도 동일하게 delete()
를 이용하면 되고 내용은 위의 함수들과 동일하기 때문에 생략합니다.
Future<int> delete(String table, {String? where, List<Object?>? whereArgs});