Realm Android 无法在没有主键的情况下复制或更新对象
Posted
技术标签:
【中文标题】Realm Android 无法在没有主键的情况下复制或更新对象【英文标题】:Realm Android can't copyOrUpdate object without primary key 【发布时间】: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()
。这样你就不会得到重复。 FavoriteSong
s 对于这个特定用户是唯一的吗?我不太了解您的模型之间的关系。
@Darwind - 是的,最喜欢的歌曲对这个用户来说是独一无二的,FavoriteSong 的服务器模型有一个“userId”字段,但我觉得没有必要在我的模型中包含它,因为有只有一个用户。为了详细说明这种关系,我们使用 FavoriteSong 的“label”字段作为类别指示符,因此我可以拥有多个带有“Classical”或“Hip-Hop”标签的喜爱歌曲。可能不是最好的组织方式,但这是后端开发人员决定构建的方式。
【参考方案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;
【讨论】:
以上是关于Realm Android 无法在没有主键的情况下复制或更新对象的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有主键的情况下从 mySQL 中的两个表中获取不常见的记录