Moor는 Flutter에서 로컬 데이터베이스 작업을 더욱 간편하고 효율적으로 처리할 수 있게 도와주는 Flutter용 SQLite 라이브러리입니다.
SQLite를 기반으로 하지만 SQL 쿼리를 직접 작성할 필요 없이 Dart 객체를 사용해 데이터를 다룰 수 있습니다.
Moor는 객체 지향적인 방식으로 SQLite를 제어할 수 있도록 설계되었으며, 특히 Flutter와의 통합에 매우 유용합니다.
Moor의 주요 특징 및 기능
1. 데이터 모델 정의와 관리
Moor에서는 데이터베이스 테이블을 Dart 클래스로 정의하고, 이를 기반으로 데이터를 관리합니다. 일반적으로 @Table 어노테이션을 사용하여 테이블을 정의합니다. 이를 통해 SQL 없이 객체 지향적으로 데이터를 처리할 수 있습니다.
테이블 정의
테이블을 정의할 때 각 필드에 대해 TextColumn, IntColumn, BoolColumn 등의 컬럼을 지정합니다. 예를 들어, User라는 테이블을 다음과 같이 정의할 수 있습니다.
import 'package:moor/moor.dart';
@DataClassName('User') // 데이터 모델 클래스 이름
class Users extends Table {
IntColumn get id => integer().autoIncrement()(); // 기본 키, 자동 증가
TextColumn get name => text()(); // 사용자 이름
IntColumn get age => integer()(); // 사용자 나이
TextColumn get email => text()(); // 이메일 주소
}
위와 같이 Users 테이블을 정의하며, name, age, email 등을 필드로 설정합니다. id는 자동 증가하도록 설정합니다.
2. 데이터베이스 접근: DAO (Data Access Object)
Moor에서는 DAO(Data Access Object)라는 클래스를 사용하여 데이터베이스와 상호작용합니다. DAO는 데이터를 삽입, 삭제, 업데이트, 조회하는 메서드를 제공합니다. @UseDao 어노테이션을 사용하여 DAO 클래스를 정의하고, 데이터베이스 작업을 쉽게 처리할 수 있습니다.
DAO 클래스 예시
@UseDao(tables: [Users])
class UserDao extends DatabaseAccessor<AppDatabase> with _$UserDaoMixin {
final AppDatabase db;
UserDao(this.db) : super(db);
Future<List<User>> getAllUsers() => select(users).get(); // 모든 사용자 조회
Stream<List<User>> watchAllUsers() => select(users).watch(); // 사용자 목록 실시간 스트림
Future insertUser(User user) => into(users).insert(user); // 사용자 삽입
Future updateUser(User user) => update(users).replace(user); // 사용자 업데이트
Future deleteUser(int id) => (delete(users)..where((u) => u.id.equals(id))).go(); // 사용자 삭제
}
위 코드에서 getAllUsers, insertUser, deleteUser 등의 메서드를 정의하여 Users 테이블과 상호작용합니다.
3. 쿼리와 데이터 접근
Moor는 직접 SQL 쿼리를 작성하지 않고도 Dart 코드를 통해 데이터를 조회, 삽입, 수정, 삭제할 수 있도록 해줍니다.
Dart 코드로 직접 테이블과 상호작용하며 데이터베이스 작업을 수행할 수 있습니다.
데이터 삽입
final user = UsersCompanion(
name: Value('John Doe'),
age: Value(30),
email: Value('john.doe@example.com'),
);
await userDao.insertUser(user);
데이터 조회
// 비동기적으로 모든 사용자 조회
List<User> users = await userDao.getAllUsers();
// 스트림을 사용하여 사용자 목록을 실시간으로 업데이트
Stream<List<User>> userStream = userDao.watchAllUsers();
데이터 업데이트
final user = User(id: 1, name: 'John Updated', age: 31, email: 'updated@example.com');
await userDao.updateUser(user);
데이터 삭제
await userDao.deleteUser(1); // id가 1인 사용자 삭제
4. 복잡한 쿼리 지원
Moor는 기본적인 CRUD 작업 외에도 복잡한 쿼리를 처리할 수 있습니다.
예를 들어, 조건에 맞는 데이터를 필터링하거나 정렬하는 쿼리를 쉽게 작성할 수 있습니다.
조건에 맞는 데이터 필터링
Future<List<User>> getUsersByAge(int minAge) {
return (select(users)..where((u) => u.age.isBiggerThanValue(minAge))).get();
}
정렬된 데이터 조회
Future<List<User>> getUsersSortedByName() {
return (select(users)..orderBy([(u) => OrderingTerm(expression: u.name)]))
.get();
}
조인 쿼리
Moor는 테이블 간의 조인도 지원합니다. 예를 들어, 두 테이블을 조인하여 데이터를 조회하는 쿼리를 작성할 수 있습니다.
Future<List<UserWithPost>> getUsersWithPosts() {
final query = select(users).join([
leftOuterJoin(posts, posts.userId.equalsExp(users.id)),
]);
return query.map((row) {
final user = row.readTable(users);
final post = row.readTable(posts);
return UserWithPost(user, post);
}).get();
}
5. 트랜잭션
Moor에서는 여러 데이터베이스 작업을 트랜잭션으로 묶어서 실행할 수 있습니다.
트랜잭션을 사용하면 여러 작업을 원자적으로 처리할 수 있습니다.
await db.transaction(() async {
await userDao.insertUser(User(id: 1, name: 'Alice', age: 25, email: 'alice@example.com'));
await userDao.insertUser(User(id: 2, name: 'Bob', age: 30, email: 'bob@example.com'));
});
위 코드는 insertUser 두 개의 작업을 하나의 트랜잭션으로 묶어서 실행합니다.
6. JSON 데이터 저장 (List, Map 등)
Moor는 Dart의 복합 데이터 형식인 List, Map, DateTime 등을 손쉽게 저장하고 관리할 수 있습니다. 복합 데이터를 저장할 때는 TextColumn을 사용하고 JSON 형식으로 직렬화하여 저장합니다.
List<String> 저장하기
TextColumn get tags => text().nullable()(); // JSON 문자열로 저장
데이터 삽입 시 List<String>을 JSON 문자열로 직렬화하여 저장합니다.
final user = UsersCompanion(
name: Value('John Doe'),
age: Value(30),
tags: Value('["developer", "flutter"]'), // List<String> -> JSON String
);
await userDao.insertUser(user);
Map 저장하기
TextColumn get profile => text().nullable()(); // JSON 문자열로 저장
Map도 JSON 문자열로 직렬화하여 저장합니다.
final user = UsersCompanion(
name: Value('Jane Doe'),
age: Value(28),
profile: Value('{"email": "jane.doe@example.com", "address": "Seoul"}'), // Map -> JSON String
);
await userDao.insertUser(user);
7. 스트림과 리액티브 프로그래밍
Moor는 스트림을 지원하여 데이터베이스의 변화에 반응하는 리액티브한 앱을 만들 수 있습니다. 예를 들어, 사용자 목록을 스트림으로 받아서 실시간으로 UI를 갱신할 수 있습니다.
Stream<List<User>> watchAllUsers() => select(users).watch();
위와 같이 watch 메서드를 사용하여 테이블의 변화를 실시간으로 감지하고 UI에 반영할 수 있습니다.
8. 데이터베이스 마이그레이션
Moor에서는 데이터베이스의 버전 관리와 마이그레이션을 지원합니다.
앱의 버전이 업그레이드되면서 데이터베이스 구조를 변경할 때 schemaVersion을 관리하여 데이터베이스를 안전하게 마이그레이션할 수 있습니다.
@override
int get schemaVersion => 2; // 데이터베이스 버전
Moor는 버전 업그레이드 시 자동으로 마이그레이션을 처리하거나, 필요에 따라 커스텀 마이그레이션을 구현할 수 있습니다.
구독!! 공감과 댓글,
광고 클릭은 저에게 큰 힘이 됩니다.
Starting Google Play App Distribution! "Tester Share" for Recruiting 20 Testers for a Closed Test.
'Flutter > Package' 카테고리의 다른 글
플러터에서 http 패키지를 사용한 The Movie Database API사용 방법 (2) | 2024.11.12 |
---|---|
플러터에서 Freezed 플러그인! Entity Code Generation은 이거 하나로 끝 (1) | 2024.10.27 |
Flutter Launcher Icons 사용하기: 초보자를 위한 쉬운 가이드 (6) | 2024.10.14 |
플러터에서 ML 모델 사용하기: 초보자를 위한 완벽 가이드 (5) | 2024.10.11 |
플러터에서 get_it 패키지 사용 방법과 옵션 쉽게 이해하기 [의존성 주입] (5) | 2024.09.12 |