Realm一對多及多對多反向連接查詢

Realm backlinks, queries to linking objects, and changes in schema design

In Realm Android 3.4.0-SNAPSHOT, support for queries across backlinks got merged, and with the next release, inverse relations will be out of beta.

This allows us to simplify the Realm schema by replacing many bi-directional links with uni-directional ones, and replace the links “pointing back” with backlinks.


Realm反連接,查詢連接的對象及schema設計中的改變

在Realm的Android 3.4.0-嚐鮮版中,已合併對反向連接交叉查詢的支持,在下一個發佈版本中,反向關係將正式可用。

使用單向連接替換衆多雙向連接,並用反向連接替換“指向”連接,這允許我們簡化Realm數據庫。


@LinkingObjects
The support for inverse relations was initially added in 3.1.0, but it didn’t support queries across them until now. This essentially means that for any relation you have in your schema (either 0..1 or 0..*), you can now see the objects that are linking to your current object.
For example, we have the following model classes:

@連接對象

最初是在3.1.0中增加對反向關係的支持,但是直到目前還不支持它們之間的交叉查詢。本質上是說,在數據庫中的任何關係(或者是0..1,或者是0..x),你能看到連接到當前對象的對象們。如,我們有以下模型類:

public class Dog extends RealmObject {
    @PrimaryKey
    private String id;
  
    private int age;
  
    // getters, setters
}

public class Person extends RealmObject {
    @PrimaryKey
    private String id;
  
    private String name;
  
    // getters, setters
}

And what we want to specify is that a Person can have multiple dogs. Let’s say that a Dog can only be owned by one person. Previously, you would have to create the following schema:

我們想說的是,一個人能有好幾只狗。又比如一個狗只能有一個主人。以前,你得創建如下數據圖:

public class Dog extends RealmObject {
    @PrimaryKey
    private String id;
  
    private int age;
  
    private Person owner; // <--- !!!
    
    // getters, setters
}

public class Person extends RealmObject {
    @PrimaryKey
    private String id;
  
    private String name;
  
    private RealmList<Dog> dogs;
  
    // getters, setters
}

// creating objects
r.executeTransaction((realm) -> {
    Dog dog = realm.createObject(Dog.class, "dogId");
    Person person = realm.createObject(Person.class, "personId");
    person.getDogs().add(dog);
    dog.setOwner(person); // <--- !!!
});

// link query
RealmResults<Dog> dogs = realm.where(Dog.class)
                              .equalTo("owner.name", "Jack")
                              .findAll();

And while a Dog is technically owned by a Person, we don’t really need to say that a “Dog belongs to a Person”, right?
We say the Person owns the Dog. Then we implicitly know that the Dog is owned by that given Person.
This is an inverse relationship: if a Person owns a Dog, then that Dog is owned by that Person.

We can now replace manually established bi-directional links, with automatically managed backlinks to linking objects.


準確來說,當一隻狗被一個人擁有時,我們不必說“狗屬於一個人”,對吧?

我們說人擁有狗,隱含的意思是狗被指定的人擁有。

這是一個反向關係:如果一個人擁有一隻狗,那麼那麼那隻狗被那個人擁有。

現在,對於連接對象,我們能使用可管理反向連接來替換手動建立的雙向連接。

public class Dog extends RealmObject {
    @PrimaryKey
    private String id;
  
    private int age;
  
    @LinkingObjects("dogs") // <-- !
    private final RealmResults<Person> owners = null; // <-- !
    
    // getters, setters
}

public class Person extends RealmObject {
    @PrimaryKey
    private String id;
  
    private String name;
  
    private RealmList<Dog> dogs;
  
    // getters, setters
}

// creating objects
r.executeTransaction((realm) -> {
    Dog dog = realm.createObject(Dog.class, "dogId");
    Person person = realm.createObject(Person.class, "personId");
    person.getDogs().add(dog);
    // dog.getOwners() will automatically contain `person`
});

// link query
RealmResults<Dog> dogs = realm.where(Dog.class)
                              .equalTo("owners.name", "Jack")
                              .findAll();

Every relationship, either 0..1 or 0..* creates their corresponding backlinks in the target class.
One thing to note is that an inverse relationship can only be seen as 0..* meaning it must be declared as RealmResults<T>. Also, when declared, it is final and the accessors are transformed to return the managed linking objects.
With that, we no longer need to manually manage the owners of the Dog, it’s managed by Realm automatically :)

What’s worth a mention is that backlink fields don’t need to be added with migration, but if you remove the list or property that points back, then of course a migration is needed to remove that field.


每一個關係,不管是0..1還是0..*,都在目標類中創建它們對應的反向連接。

要注意一個事情,一個反向關係只能被視作0..*,意思是它必須被聲明爲 RealmResults<T>。當定義它時,應使用final修飾,而且訪問符被轉變以返回可管理連接對象。

有了它,我們不必再手動管理狗的擁有者,它被Realm自動管理了。 :)

值得提出的是,反向連接字段在增加時不需要遷移,但是如果你移除此list或指回的屬性,則當然需要一個遷移來移除字段。(注:意思是說,增加連接字段不會改變表結構,不用做數據遷移,但是刪除它則需要做


Conclusion
Automatic inverse relations will simplify Realm schema design, and schema maintenance. Hopefully this article gave you a quickstart for how to work with @LinkingObjects.


結論

自動反向關係將簡化Realm數據結構設計和數據結構維護。本文希望給你一個快速指導:怎樣使用@LinkingObjects進行工作?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章