Room Persistence更新时删除子项

15

我正在使用Room库在我的Android应用程序中持久化数据。我有两个主要的表,即任务和组。它们之间是一对多的关系,一个任务只能属于一个组,但一个组可以属于多个任务。

持久性工作正常,但问题是当我尝试从一个组更新信息时,与该组相关的所有任务都被删除。

以下是我的实体和DAO配置:

任务实体

@Entity(tableName = "task",
        foreignKeys = {
                @ForeignKey(
                        entity = Group.class,
                        parentColumns = "id",
                        childColumns = "groupId",
                        onDelete = CASCADE,
                        onUpdate = RESTRICT
                )},
        indices = {@Index(value = "id"), @Index(value = "groupId")}
)
public class Task {

    @PrimaryKey(autoGenerate = true)
    private int id;
    private String name;
    private int groupId;

    public Task(int id, String name, int groupId) {
        this.id = id;
        this.name = name;
        this.groupId = groupId;
    }

}

群体实体

 @Entity(tableName = "group")
public class Group {

    @PrimaryKey(autoGenerate = true)
    private int id;
    private String name;

    public Group(int id, String name) {
        this.id = id;
        this.name = name;
    }

}

任务DAO

@Dao
public interface TaskDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void addTask(Task task);

    @Query("select * from task")
    public List<Task> listAllTasks();

    @Query("select * from task where id = :taskId")
    public Task getTask(int taskId);

    @Update(onConflict = OnConflictStrategy.REPLACE)
    void updateTask(Task task);

    @Query("delete from task")
    void removeAllTasks();

    @Delete
    void delete(Task task);
}

群组DAO

@Dao
public interface GroupDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void addGroup(Group group);

    @Query("select * from `group`")
    public List<Group> listAllGroups();

    @Query("select * from `group` where id = :groupId")
    public Group getGroup(long groupId);

    @Update(onConflict = OnConflictStrategy.REPLACE)
    void updateGroup(Group group);

    @Query("delete from `group`")
    void removeAllGroups();

    @Delete
    void delete(Group group);

}

在任务类中实体声明中将 OnUpdate 更改为 RESTRICT、CASCADE 或 NO_ACTION 并不起作用。

我将非常感激任何帮助。谢谢。


4
你试过不加ondelete=cascade吗?当使用"REPLACE"冲突解决策略删除行以满足约束条件时,只有在启用了递归触发器时才会触发删除触发器。 - lib4backer
2
是的,它可以工作。但onDelete必须是CASCADE,否则我会有外键约束失败。你的评论让我找到了问题所在。我正在使用addGroup()来创建一个新行或更新现有行。这就是为什么每次都会调用REPLACE并触发onDelete行为的原因。谢谢! - Herbert Souza Silva
很高兴知道它有所帮助。 - lib4backer
这是我找到的冲突策略解决方案链接,不错。https://sqlite.org/lang_conflict.html - lib4backer
那么这个问题的确切解决方案是什么?你需要更改这个方法: @Insert(onConflict = OnConflictStrategy.REPLACE) void addGroup(Group group); ? - Tom Wayne
1
@JosefHruška 不是的。上面提到的所有方法都是正确的。唯一错误的是在尝试更新信息时我使用了 addGroup 方法。很简单,对于新资源使用添加(add)操作,对于已有资源使用更新(update)操作。 - Herbert Souza Silva
1个回答

9

如SQLite文档中所述: 当出现UNIQUE或PRIMARY KEY约束冲突时,REPLACE算法会在插入或更新当前行之前删除导致约束冲突的预先存在的行,并且命令继续正常执行。如果出现NOT NULL约束冲突,则REPLACE冲突解决方案将使用默认值替换该列的NULL值,或者如果该列没有默认值,则使用ABORT算法。如果出现CHECK约束或外键约束冲突,则REPLACE冲突解决算法的工作方式类似于ABORT。

当REPLACE冲突解决策略为了满足约束而删除行时,只有在启用递归触发器的情况下才会触发删除触发器。

并如Google文档所述:默认情况下,所有RoomDatabases都使用内存存储TEMP表并启用递归触发器。

结论:由于您正在使用REPLACE ConflictStrategy和外键CASCADE将删除父实体,因此每个子行在尝试插入已存在的父行时都会被删除。

解决方案: 使用@Query来更新组,如下所示。

@Query("UPDATE groups SET columnToUpdate1 = :value1, columnToUpdate2 = :value2 WHERE id=:id")
void updateGroup(int id, value1,value2);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接