Flutter

Flutter SQLite 사용하기

알렌보이스 2022. 10. 3. 19:23
728x90

Untitled

이번 포스팅에서는 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을 넣어주었습니다.

ConflictAlgorithminsert 과정 중 충돌이 발생하였을 때 방법을 설정하는 것으로

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});
728x90