하얀설표 블로그




dart/flutter drift insert, update 예제





( 수정됨)


코드

models.py

# models.py
import 'package:drift/drift.dart';

// https://drift.simonbinder.eu/docs/getting-started/advanced_dart_tables/

@DataClassName('InseTable')
class Inse extends Table {
  // autoIncrement
  IntColumn get id => integer().autoIncrement()();
  // null 허용
  IntColumn get category => integer().nullable()();
  // bool
  // 기본값을 false로 지정
  BoolColumn get enable => boolean().withDefault(const Constant(false))();
  // dateTime
  DateTimeColumn get date => dateTime()();
  // String
  // 최소/최대 길이 제한
  TextColumn get title => text().withLength(min: 1, max: 32)();
  //
  TextColumn get content => text().named('body')();
}

database.dart

# database.dart
import 'dart:io';
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:sqlite3/sqlite3.dart';
// dart에서 사용하기 위해 주석처리
// import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart';
import 'package:example/Drift/models.dart';

part 'database.g.dart';

@DriftDatabase(tables: [Inse])
class Handle extends _$Handle {
  Handle() : super(_openConnection());

  @override
  int get schemaVersion => 1;
  // 테이블 전체 데이터 가져오기(Furture)
  Future<List<InseTable>> get allTodoItems => select(inse).get();
  // 테이블 limit 갯수만큼 데이터 가져오기(Furture)
  Future limitTodos(int limit, {int? offset}) {
    return (select(inse)..limit(limit, offset: offset)).get();
  }
  // 특정 데이터 가져오기(Future)
  Future<InseTable> findById(int id) {
    return (select(inse)..where((table) => table.id.equals(id))).getSingle();
  }
  // 수정하기
  Future updateTodo(InseTable entry) {
    return update(inse).replace(entry);
  }
  // 수정하기2
  Future updateTodoCom(InseCompanion entry) {
    return update(inse).replace(entry);
  }
  // 삽입
  Future<int> insertTodo(InseCompanion entry) {
    return into(inse).insert(entry);
  }
  // 삭제
  Future delTodo(int id) {
    return (delete(inse)..where((table) => table.id.equals(id))).go();
  }
}

LazyDatabase _openConnection() {
  return LazyDatabase(() async {
    final file = File('db.sqlite');
    return NativeDatabase.createInBackground(file);
    // return NativeDatabase.memory();
  });
}

main.dart

# main.dart
import 'package:example/Drift/database.dart';

void main() async {
  final db = await Handle();
  var a = await db.allTodoItems;
  print('[');
  for (final i in a) {print('  $i');}
  print(']');
  print('='*20);
  await db.insertTodo(InseCompanion.insert(
      date: DateTime.now(), title: '222', content: '2'
  )
  );
  a = await db.allTodoItems;
  print('[');
  for (final i in a) {print('  $i,');}
  print(']');
  print('='*20);print('[');
  await db.insertTodo(InseCompanion.insert(
      date: DateTime.now(), title: '333', content: '33'
  )
  );
  a = await db.allTodoItems;
  print('[');
  for (final i in a) {print('  $i,');}
  print(']');
  print('='*20);print('[');
  await db.insertTodo(InseCompanion.insert(
      date: DateTime.now(), title: '444', content: '4'
  )
  );
  await db.updateTodo(InseTable(id: 2, enable: true, date: DateTime.now(), title: '555', content: '5'));
  await db.updateTodoCom(
      InseCompanion.insert(
        id: Value(3),
        title: '34567',
        content: '76543', date: DateTime.now()
      )
  );
  a = await db.allTodoItems;
  print('[');
  for (final i in a) {print('  $i,');}
  print(']');
  print('='*20);print('[');
}

설명

dart/flutter에서 drift를 포함해 sqlite를 조작하려면 사전 작업이 반드시 필요하다.
이 작업들을 모른다면 어떤 작업을 해야 하는지 확인하길 바란다.

dart/flutter에서 사용 가능한 패키지인 drift에서 사용가능한 기본적인 명령과 각 Column의 속성을 작성한 코드다.
개인적으로 sqlite에서 사용 가능한 값은 int, string, bool 3가지만 사용했는데, 이 패키지는 int, string, bool에 더해 datetime 속성도 지원한다.
그밖에도 다른 속성도 지원하지만 현재 내가 사용할 줄 아는 속성이 이 4가지뿐이니 생략한다.

@DataClassName

데이터 테이블은 보통 models.dart에 작성된 class 이름을 따라가지만, @DataClassName('{데이터 클래스 명칭}')을 통해 return하는 데이터의 Type 명칭을 정의할 수 있다.
database.dart를 보면 type과 class 명칭이 다른 것을 알 수 있다.

@DriftDatabase(tables: [])

@DriftDatabase(tables: [])을 통해 1개의 데이터베이스 핸들 class에서 조작할 table의 갯수를 변경할 수 있다.
즉, 1개의 핸들에서 2개 이상의 데이터 테이블을 조작할 수 있다는 것이다.

2개 이상의 데이터 테이블을 조작하는 경우 각 테이블을 조작하는 명령을 추가하거나, db에 존재하는 table을 선택해 직접 명령하는 것도 가능하다.
db를 호출하고, db에 존재하는 table을 선택한 다음, table에서 할 작업을 명령하는 것은 pub.dev의 dirft 페이지에서 제공하는 Example 페이지를 참고하면 된다.

아니면 각 테이블마다 사용할 핸들 class를 따로따로 만들어 사용하는 것도 가능하다.

실행 예시

기능 자체는 꽤 많지만, 당장 자주 사용하는 기능인 데이터 읽기/추가/삭제/수정 작업만 main.dart에서 실행하도록 예시 코드를 작성해두었다.
main.dart를 실행하면 다음과 같이 데이터가 추가되고, upsert 명령으로 데이터가 수정되는 것도 확인할 수 있다.
마지막에는 불러온 데이터에서 각 Column별 type을 출력하도록 해두었다.

[
]
====================
[
  InseTable(id: 1, category: null, enable: false, date: 2023-12-07 14:07:18.000, title: 222, content: 2),
]
====================
[
  InseTable(id: 1, category: null, enable: false, date: 2023-12-07 14:07:18.000, title: 222, content: 2),
  InseTable(id: 2, category: null, enable: false, date: 2023-12-07 14:07:18.000, title: 333, content: 33),
]
====================
[
  InseTable(id: 1, category: null, enable: false, date: 2023-12-07 14:07:18.000, title: 222, content: 2),
  InseTable(id: 2, category: null, enable: true, date: 2023-12-07 14:07:18.000, title: 555, content: 5),
  InseTable(id: 3, category: null, enable: false, date: 2023-12-07 14:07:18.000, title: 34567, content: 76543),
]
====================

upsert 명령

upsert 명령은 update와 insert의 합성어로 보인다.
실제로 해당 명령 사용시 중복되는 데이터가 있으면 update 작업을 하고, 중복되는 데이터가 없으면 insert 작업을 하기 때문이다.

upsert 명령 예제는 이 페이지에서 확인할 수 있다.

Companion

예제에서 Table 객체와 Companion 객체를 혼용해서 사용했는데, 이 내용은 이 페이지에서 확인할 수 있다.

Primary Key

조건 또는 환경에 따라 update 작업이 적용되지 않을 수 있다.
이는 Primary Key가 잘못 지정되어서 그런 것인데, 그런 경우 models.dart에서 Primary Key를 지정해주는 명령을 하면 된다.
보통 autoIncrement()가 적용된 IntColumn을 기본으로 Primary Key로 인식한다고 한다.

다른 Column을 지정하고 싶다면 위에 링크한 upsert 명령 예제에서 그 방법을 확인할 수 있다.


공감 : 0







white.seolpyo.com