【问题标题】:Realm Android can't copyOrUpdate object without primary keyRealm Android 无法在没有主键的情况下复制或更新对象
【发布时间】:2017-02-08 17:56:58
【问题描述】:

我正在使用以下架构,Realm 定义了一个拥有收藏歌曲列表的用户:

public class User extends RealmObject { 
    @PrimaryKey
    Long id;
    RealmList<FavoriteSong> favoriteSongs;  
}

public class FavoriteSong extends RealmObject { 
    String label;
    Song song;
}

public class Song extends RealmObject {
    @PrimaryKey
    Long id;
    String title;   
}

我的应用模型基本上反映了服务器模型。所以当我收到一首新的 FavoriteSong 时,我想将它保存到领域:

FavoriteSong favoriteSong = ...favorite song from server
mRealm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            // Add a new FavoriteSong
            realm.copyToRealm(favoriteSong); // Fails with Value already exists: 0
        }

这会失败,因为FavoriteSong 中包含的歌曲已经存在于领域中,违反了主键约束。

一种解决方法是将FavoriteSong标签设置为主键:

public class FavoriteSong extends RealmObject { 
    @Primary
    String label;
    Song song;
}

然后使用copyToRealmOrUpdate()代替copyToRealm(),它在插入之前检查所有关系的主键:

realm.copyToRealmOrUpdate(favoriteSong);

这可行,但不幸的是我不能这样做,因为可以有多个具有相同标签的收藏歌曲,而主键不允许这样做。

知道如何在没有主键且不违反主键约束的情况下将 FavoriteSong 添加到领域吗?

【问题讨论】:

  • 您来自服务器的FavoriteSong 是否包含song;
  • @EpicPandaForce - 是的
  • 这是您问题的根源:FavoriteSong 没有主键,但copyToRealm() 会尝试将对象与喜欢的歌曲一起保存在其中
  • 那你为什么不给FavoriteSong添加唯一的ID呢?例如,使用UUID.randomUUID()。这样你就不会得到重复。 FavoriteSongs 对于这个特定用户是唯一的吗?我不太了解您的模型之间的关系。
  • @Darwind - 是的,最喜欢的歌曲对这个用户来说是独一无二的,FavoriteSong 的服务器模型有一个“userId”字段,但我觉得没有必要在我的模型中包含它,因为有只有一个用户。为了详细说明这种关系,我们使用 FavoriteSong 的“label”字段作为类别指示符,因此我可以拥有多个带有“Classical”或“Hip-Hop”标签的喜爱歌曲。可能不是最好的组织方式,但这是后端开发人员决定构建的方式。

标签: android realm


【解决方案1】:

请尝试

FavoriteSong favoriteSong = ...favorite song from server
mRealm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            Song tempSong = favoriteSong.getSong();
            favoriteSong.setSong(null);
            FavoriteSong savedFavoriteSong = realm.copyToRealm(favoriteSong);
            Song dbSong = realm.where(Song.class).equalTo(SongFields.ID, tempSong.getId()).findFirst();
            if(dbSong == null) {
                dbSong = realm.copyToRealmOrUpdate(tempSong);
            }
            savedFavoriteSong.setSong(dbSong);
        }

SongFields 假设您使用的是https://github.com/cmelchior/realmfieldnameshelper

【讨论】:

  • 另一个被EpicPanda拯救的灵魂^^.
  • 好的,所以我很愚蠢,结果我正在寻找的是试图用标签和歌曲定义一个复合主键。对困惑感到抱歉。这似乎是 Realm 的热门话题,我有几个问题可能对其他用户有帮助。如果我发布另一个关于此的具体问题,您能帮帮我吗?
  • 复合键意味着您应该将两个属性一起附加到一个字符串字段中。
  • 您只需要确保在Realm中创建RealmObject时获得复合ID,因为一旦创建了对象就无法修改PK。
  • 然后对你的 Realm 访问做一个抽象
【解决方案2】:

使用

import io.realm.annotations.PrimaryKey; 

而不是

import androidx.room.PrimaryKey;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-09
    • 2019-08-02
    • 1970-01-01
    • 2021-08-23
    • 2023-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多