동기 Realm 마이그레이션 가이드

Realm 모바일 플랫폼에 관심 있는 모바일 개발자들은 마이그레이션에 대한 질문을 자주 합니다. Realm 모바일 플랫폼이 실제로 얼마나 간단하고 직관적인 접근 방법으로 마이그레이션하는지 알려드리겠습니다.

  1. 스키마 변경은 자동입니다 - 스키마 버전이나 마이그레이션 블럭을 설정하지 않아도 됩니다.
  2. 스키마 변경은 이전 버전과 호환됩니다 - 기존 클라이언트는 새로운 버전과 계속 동기화됩니다.
  3. 속성이나 클래스를 추가하거나 제거하는 스키마 변경을 지원합니다.

예제를 통해 자세히 알아보겠습니다. 앱에 하나의 문자열 속성을 가지는 Dog라는 클래스 하나가 있다고 생각해 볼까요?

class Dog: Object {
	dynamic var name = ""
}
class Dog : RealmObject() {
   var name = ""
}
public class Dog extends RealmObject {
    public String name = "";
    // getter / setter
}

앱을 배포한 후 새로운 모델인 Person을 추가해서 업데이트하고 싶다면 어떻게 할까요? 해당 클래스와 관련 속성을 추가하기만 하면 됩니다.

class Dog: Object {
	dynamic var name = ""
	dynamic var owner: Person?
}

class Person: Object {
	dynamic var name = ""
	dynamic var birthdate: NSDate? = nil
}

let syncServerURL = URL(string: "realm://localhost:9080/Dogs")!
// schemaVersion이나 migrationBlock을 설정할 필요가 없습니다
let config = Realm.Configuration(syncConfiguration: SyncConfiguration(user: user, realmURL: syncServerURL))

let realm = try! Realm(configuration: config)
class Dog : RealmObject() {
    var name = ""
    var owner: Person? = null
}

class Person : RealmObject() {
    var name = ""
    var birthdate: Date? = null
}

val syncServerURL = "realm://localhost:9080/Dogs"
val config = SyncConfiguration.Builder(user, syncServerURL).build()

val realm = Realm.getInstance(config)
public class Dog extends RealmObject {
  private String name = "";
  private Person owner;
  // getter / setter
}

public class Person extends RealmObject {
  private String name = "";
  private Date birthdate;
  // getter / setter
}

String syncServerURL = "realm://localhost:9080/Dogs"
SyncConfiguration config = new SyncConfiguration.Builder(user, syncServerURL).build();

Realm realm = Realm.getInstance(config);

이런 개발 뉴스를 더 만나보세요

정말 간단하죠? 이전 버전 사용자는 최신 버전과 계속 동기화되면서 Dog의 변경 사항만 표시됩니다. 다음으로 Person에서 생년월일을 제거하는 세 번째 버전을 만들려면 어떻게 할까요?

class Dog: Object {
	dynamic var name = ""
	dynamic var owner: Person?
}

class Person: Object {
	dynamic var name = ""
}

let syncServerURL = URL(string: "realm://localhost:9080/Dogs")!
// schemaVersion이나 migrationBlock을 설정할 필요가 없습니다
let config = Realm.Configuration(syncConfiguration: SyncConfiguration(user: user, realmURL: syncServerURL))

let realm = try! Realm(configuration: config)
class Dog : RealmObject() {
  var name = ""
  var owner: Person? = null
}

class Person : RealmObject() {
  var name = ""
}

val syncServerURL = "realm://localhost:9080/Dogs"
// schemaVersion이나 migrationBlock을 설정할 필요가 없습니다
val config = SyncConfiguration.Builder(user, syncServerURL).build()

val realm = Realm.getInstance(config)
public class Dog extends RealmObject {
  private String name = "";
  private Person owner;
  // getter / setter
}

public class Person extends RealmObject {
  private String name = ""
  // getter / setter
}

String syncServerURL = "realm://localhost:9080/Dogs"
// schemaVersion이나 migrationBlock을 설정할 필요가 없습니다
SyncConfiguration config = new SyncConfiguration.Builder(user, syncServerURL).build();

Realm realm = Realm.getInstance(config);

이번에도 정말 간단하죠! 내부적으로 Realm은 이전 버전과의 하위 호환성을 유지하기 위해 저장 레이어에 생년월일 열을 계속 유지합니다. 세 번째 버전에 의해 Person 객체가 생성되면 두 번째 버전의 클라이언트는 생년월일에 nil 값을 갖습니다. 옵셔널이 아닌 속성이라면 기본값이 대신 삽입됩니다.

이런 간단한 접근 방식으로 동기 Realm을 여러 버전에서 쉽게 사용할 수 있습니다. 주의할 점은 속성이나 클래스를 추가하거나 제거하는 것은 자동으로 지원되지만, 어떤 스키마 변경 사항은 지원되지 않는다는 것입니다.

  • 같은 이름의 속성 타입을 변경하는 경우
  • 기본 키를 변경하는 경우
  • 속성을 옵셔널에서 필수로, 혹은 필수에서 옵셔널로 변경하는 경우

이런 작업은 이전 버전과 호환되지 않으므로 스키마 변경 사항이 적용된 새로운 동기 Realm을 만들고 필요한 경우 이전 Realm의 데이터를 새 Realm으로 복사해야 합니다.

class Dog: Object {
	dynamic var name = ""
	dynamic var owner: Person?
}

class Person: Object {
	dynamic var name = ""
}

class PersonV2: Object {
	dynamic var name: String? = nil
}

var syncServerURL = URL(string: "realm://localhost:9080/Dogs")!
var config = Realm.Configuration(syncConfiguration: SyncConfiguration(user: user, realmURL: syncServerURL))
// 초기 객체 타입 제한
config.objectTypes: [Dog.self, Person.self]

let initialRealm = try! Realm(configuration: config)


syncServerURL = URL(string: "realm://localhost:9080/DogsV2")!
config = Realm.Configuration(syncConfiguration: SyncConfiguration(user: user, realmURL: syncServerURL))
// 새 객체 타입 제한
config.objectTypes: [Dog.self, PersonV2.self]


let newRealm = try! Realm(configuration: config)
class Dog : RealmObject() {
    var name = ""
    var owner: Person? = null
}

class Person : RealmObject() {
    var name = ""
}

class PersonV2 : RealmObject() {
    var name = ""
}


@RealmModule(classes = arrayOf(Person::class, Dog::class))
class InitialModule

val syncServerURL = "realm://localhost:9080/Dogs"
val config = SyncConfiguration.Builder(user, syncServerURL)
            .modules(InitialModule())
            .build()
// 초기 객체 타입 제한
val initialRealm = Realm.getInstance(config)


@RealmModule(classes = arrayOf(Person::class, DogV2::class))
class NewModule

val syncServerURL = "realm://localhost:9080/DogsV2"
val config = SyncConfiguration.Builder(user, syncServerURL)
            .modules(InitialModule())
            .build()
// 새 객체 타입 제한
val newRealm = Realm.getInstance(config)
public class Dog extends RealmObject {
  private String name = "";
  private Person owner;
  // getter / setter
}

public class Person extends RealmObject {
  private String name = "";
  // getter / setter
}

public class PersonV2 extends RealmObject {
  private String name = "";
  // getter / setter
}

@RealmModule(classes = { Person.class, Dog.class }) class InitialModule {}

String syncServerURL = "realm://localhost:9080/Dogs"
SyncConfiguration config = new SyncConfiguration.Builder(user, syncServerURL)
              .modules(new InitialModule())
              .build();
// 초기 객체 타입 제한
Realm initialRealm = Realm.getInstance(config);



@RealmModule(classes = { Person.class, DogV2.class }) class NewModule {}

String syncServerURL = "realm://localhost:9080/Dogs"
SyncConfiguration config = new SyncConfiguration.Builder(user, syncServerURL)
              .modules(new NewModule())
              .build();
// 새 객체 타입 제한
Realm initialRealm = Realm.getInstance(config);

다음: 안드로이드를 위한 Realm #4: SqliteToRealm: 작은 경험 이야기

General link arrow white

컨텐츠에 대하여

이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.


Adam Fish

Adam is the Director of Product at Realm, where he manages the product development for currently supported mobile platforms and upcoming new products. He has a strong background in entrepreneurship and software development, having previously co-founded Roobiq, a mobile-first sales productivity app used by sales teams worldwide.

4 design patterns for a RESTless mobile integration »

close