Isar 개념 2 - Isar 데이터베이스 CRUD (Create, Read, Update, Delete)

pharmDev·2024년 12월 31일

isar

목록 보기
2/7

Isar 데이터베이스 CRUD (Create, Read, Update, Delete)

Isar 데이터베이스는 Flutter/Dart 애플리케이션에서 강력하면서도 사용하기 쉬운 NoSQL 데이터베이스입니다. 이 문서에서는 Isar를 사용하여 데이터를 생성, 읽기, 수정 및 삭제하는 방법을 초급 수준의 Dart 사용자도 이해할 수 있도록 자세히 설명합니다.


1. Isar 열기

Isar를 사용하기 전에 데이터베이스를 열어야 합니다. 이 작업은 데이터베이스를 읽기 및 쓰기 작업에 사용할 준비를 합니다. 데이터베이스는 영구 디스크 저장소에 저장되며, 경로를 지정할 수도 있습니다.

// Isar 인스턴스를 열기 위한 코드 예시
final isar = await Isar.open(
  schemas: [MySchema], // 여기서 `MySchema`는 데이터베이스에 저장할 데이터 구조를 나타냅니다. 이 구조는 Dart 코드에서 정의됩니다. 예를 들어, 사용자 데이터를 저장하려면 User 클래스와 같은 스키마를 만들어야 합니다. // 스키마는 데이터베이스에 저장할 데이터 구조를 정의합니다. 
  directory: "/data", // 여기에서 `/data`는 데이터베이스 파일을 저장할 디렉토리를 지정합니다. 그러나 모든 앱에서 동작하지 않을 수 있으니, 앱의 파일 저장 경로가 올바른지 확인하는 것이 중요합니다. 예를 들어, Flutter에서는 `path_provider` 패키지를 사용해 권장 경로를 설정할 수 있습니다.
);

// 예를 들어, 아래와 같은 스키마를 정의할 수 있습니다:

import 'package:isar/isar.dart';

()
class User {
  // 자동 증가 ID 필드
  Id id = Isar.autoIncrement; 

  // 사용자의 이름 (필수 필드)
  late String name; 

  // 사용자의 나이 (필수 필드)
  late int age;

  // 선택적 이메일 필드 (null 허용)
  String? email;
}

// 위 코드에서:
// - `@Collection()` 어노테이션은 Isar에서 이 클래스가 데이터베이스 테이블과 같음을 의미합니다.
// - `Id` 필드는 객체를 고유하게 식별하며 자동으로 증가합니다.
// - `late` 키워드는 필수 입력을 의미합니다.
// - `String?` 타입은 null 값을 허용하는 선택 필드를 나타냅니다.

주요 설정 옵션

설정설명
schemas데이터베이스에서 사용할 스키마 목록을 정의합니다.
directory데이터 파일을 저장할 디렉토리를 지정합니다. (기본값: 앱 디렉토리)
inspectortrue로 설정하면 Isar Inspector를 활성화할 수 있습니다.

schemas에 사용할 스키마 이름 찾기

데이터 구조를 나타내는 클래스를 이미 작성한 상태라면, Isar가 자동으로 생성한 스키마 파일에서 MySchema에 해당하는 이름을 찾을 수 있습니다. 이를 찾는 방법은 다음과 같습니다:

  1. Isar Code Generator 사용: Isar는 build_runner를 사용하여 .g.dart 파일에 스키마 정보를 생성합니다.

  2. 빌드 실행: 프로젝트 루트에서 아래 명령어를 실행하세요.

    flutter pub run build_runner build
  3. 생성된 파일 확인: 작성한 데이터 구조 클래스(예: User)와 관련된 .g.dart 파일이 생성됩니다. 이 파일은 Dart 파일과 같은 경로에 생성됩니다.

  4. 스키마 이름 찾기: 생성된 .g.dart 파일을 열어보면 다음과 같은 내용이 포함되어 있습니다:

    const UserSchema = CollectionSchema(
      name: 'User',
      id: 1234567890, // 스키마 고유 ID
      properties: {...},
      ...
    );
  5. 스키마 이름 자동 추천: IDE에서 schemas:에 대괄호를 열고 자동 완성 기능(예: IntelliJ나 VSCode)을 사용하면 UserSchema 같은 스키마 이름이 추천됩니다.

  6. 참고 사항:

    • build_runner는 데이터를 정의할 때마다 실행해야 합니다.
    • 스키마 이름은 클래스 이름 뒤에 Schema를 붙인 형태로 자동 생성됩니다.

권장 경로 설정하기

데이터베이스 파일 경로로 단순히 "/data"를 사용하는 것은 모든 환경에서 동작하지 않을 수 있습니다. Flutter 앱에서는 path_provider 패키지를 사용해 안전한 경로를 지정하는 것이 좋습니다. 아래는 안전한 경로를 설정하는 예시입니다:

import 'package:path_provider/path_provider.dart';

// 안전한 디렉토리 경로 가져오기
final directory = (await getApplicationDocumentsDirectory()).path;

// Isar 데이터베이스 열기
final isar = await Isar.open(
  schemas: [UserSchema],
  directory: directory, // 안전한 경로를 지정
);

이 방법은 운영 체제에 맞는 적절한 경로를 반환하며, 저장소 관련 문제를 방지할 수 있습니다.

getApplicationDocumentsDirectory() 가 가르키는 경로

getApplicationDocumentsDirectory()는 Flutter의 path_provider 패키지를 통해 앱에서 데이터를 저장할 수 있는 안전한 디렉토리 경로를 제공합니다. 이 디렉토리는 아래와 같은 특징과 역할을 합니다:

  1. 플랫폼 의존적 경로:

    • Android: /data/data/<앱 패키지 이름>/files
    • iOS: 앱 샌드박스 내의 Documents 디렉토리
    • 사용자가 직접 접근하거나 수정하기 어려운 보호된 영역입니다.
  2. 안전한 데이터 저장소:

    • 앱이 삭제되면 해당 디렉토리도 자동으로 삭제됩니다.
    • 운영체제에서 앱 데이터를 안전하게 관리하도록 설계되었습니다.

이를 통해 운영체제와 환경에 맞는 적합한 경로를 자동으로 제공받아, 앱의 안정성과 데이터 관리가 크게 향상됩니다.


2. 데이터 읽기 (Read)

Isar는 데이터를 읽기 위한 다양한 메서드를 제공합니다. 다음은 주요 사용 방법입니다.

2.1 컬렉션 가져오기

컬렉션은 데이터베이스 내의 데이터 집합을 나타냅니다.

// 컬렉션 가져오기
final userCollection = isar.users; // 컬렉션 이름(users)을 사용

2.2 ID로 객체 가져오기

객체를 ID를 기준으로 검색하려면 get() 메서드를 사용합니다.

// ID로 객체를 가져오는 예시
final user = await isar.users.get(123); // ID가 123인 객체 가져오기
if (user != null) {
  print(user.name); // 사용자 이름 출력
}

2.3 쿼리로 객체 가져오기

특정 조건에 맞는 데이터를 가져오려면 쿼리를 사용할 수 있습니다.

// 조건에 맞는 데이터를 쿼리하는 예시
final users = await isar.users.filter()
  .ageGreaterThan(18) // 나이가 18세 이상인 사용자 필터링
  .findAll();

for (final user in users) {
  print(user.name); // 각 사용자의 이름 출력
}

3. 데이터 수정 (Update)

데이터베이스의 데이터를 수정하려면 put() 메서드를 사용합니다.

// 객체 수정 예시
final user = await isar.users.get(123);
if (user != null) {
  user.name = "새 이름"; // 객체의 이름 수정
  await isar.writeTxn(() async {
    await isar.users.put(user); // 수정된 객체 저장
  });
}

트랜잭션 사용

모든 쓰기 작업은 writeTxn() 내부에서 이루어져야 합니다.


4. 데이터 삽입 (Create)

새 데이터를 추가하려면 put() 메서드를 사용합니다.

// 새 객체 추가 예시
final newUser = User()
  ..id = 124
  ..name = "홍길동"
  ..age = 30;

await isar.writeTxn(() async {
  await isar.users.put(newUser); // 새 객체 저장
});

5. 데이터 삭제 (Delete)

데이터를 삭제하려면 delete() 메서드를 사용합니다.

// ID로 객체 삭제 예시
await isar.writeTxn(() async {
  final success = await isar.users.delete(123); // ID가 123인 객체 삭제
  if (success) {
    print("삭제 성공!");
  }
});

// 조건에 맞는 여러 객체 삭제 예시
await isar.writeTxn(() async {
  final count = await isar.users.filter()
    .ageLessThan(18) // 나이가 18세 미만인 사용자 필터링
    .deleteAll();
  print("$count개의 객체 삭제 완료");
});

이제 Isar 데이터베이스의 CRUD 작업을 쉽게 수행할 수 있습니다. 이를 바탕으로 더 복잡한 애플리케이션을 개발할 수 있습니다!

전체 코드 예시

import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
//dart:io가 path_provider를 통해 얻어진 경로와 함께 
//데이터베이스 파일을 안전한 디렉토리에 저장하는 데 도움을 줍니다. 
//추가적으로 File, Directory, Process와 같은 클래스도 사용할 수 있습니다.

()
class User {
  Id id = Isar.autoIncrement; // 자동 증가 ID
  late String name; // 사용자의 이름
  late int age; // 사용자의 나이
  String? email; // 선택적 이메일
}

Future<void> main() async {
  // 1. 안전한 디렉토리 경로 설정
  final directory = (await getApplicationDocumentsDirectory()).path;

  // 2. Isar 데이터베이스 열기
  final isar = await Isar.open(
    schemas: [UserSchema], // User 클래스의 스키마
    directory: directory, // 안전한 경로
  );

  // 3. 새 데이터 삽입 (Create)
  final newUser = User()
    ..name = "홍길동"
    ..age = 25
    ..email = "hong@example.com";

  await isar.writeTxn(() async {
    await isar.users.put(newUser); // 새 사용자 데이터 저장
  });
  print("새로운 사용자 추가 완료!");

  // 4. ID로 데이터 가져오기 (Read)
  final userById = await isar.users.get(newUser.id); // ID로 데이터 검색
  if (userById != null) {
    print("ID로 가져온 사용자: ${userById.name}, 나이: ${userById.age}");
  }

  // 5. 조건 쿼리로 데이터 가져오기 (Read)
  final usersOver18 = await isar.users.filter()
      .ageGreaterThan(18) // 나이가 18세 이상인 사용자
      .findAll();

  print("18세 이상 사용자 목록:");
  for (final user in usersOver18) {
    print("사용자 이름: ${user.name}, 나이: ${user.age}");
  }

  // 6. 데이터 수정 (Update)
  if (userById != null) {
    userById.name = "홍길동 수정";
    await isar.writeTxn(() async {
      await isar.users.put(userById); // 수정된 데이터 저장
    });
    print("사용자 이름 수정 완료!");
  }

  // 7. 데이터 삭제 (Delete)
  if (userById != null) {
    await isar.writeTxn(() async {
      final success = await isar.users.delete(userById.id);
      if (success) {
        print("사용자 ID ${userById.id} 삭제 성공!");
      }
    });
  }

  // 조건에 맞는 여러 데이터 삭제
  await isar.writeTxn(() async {
    final deletedCount = await isar.users.filter()
        .ageLessThan(18) // 나이가 18세 미만인 사용자 삭제
        .deleteAll();
    print("$deletedCount명의 사용자 삭제 완료!");
  });
}
profile
코딩을 배우는 초보

0개의 댓글