Android 房间 - 使用事务从两个实体中删除

Android Room - deleting from two entities using Transactions

如何使用交易从 Android 房间中的两个 table 删除数据?我不能只从一个 table 中删除数据,无论是两者还是两者都不删除。两个实体各有 1 个 DAO。

TimerDesign 是 parent,IntervalDesign 是 child

我已经设置了一个 parent - child class 因为我将需要此 class 的 1:M 关系来获得每个 parent 及其所有 children,目前尝试删除一个 parent 及其所有 children 只会从 parent table.[=18 中删除=]

public class FullTimerDesigns extends TimerDesign {
    @Embedded public TimerDesign timerDesign;

    @Relation(parentColumn = "timer_design_id", entityColumn = "parent_timer_id", entity = IntervalDesign.class)
    public List<IntervalDesign> intervalDesigns;
}

我需要指定 parent 的 ID 才能删除它及其所有 children。我知道我的 DAO @Query 没有指定 child table,我似乎也无法通过内部连接来解决这个问题。

@Dao
public interface ParentWithChildDAO {
    @Transaction
    @Query("DELETE FROM parent WHERE parent_id = :id")
    public void deleteOneParentWithAllChildren(int id);

    @Transaction
    @Query("DELETE FROM parent")
    public void deleteAllParentsWithAllChildren();
}

我能找到的大多数示例和 documentation Room 1:m 映射 class 仅显示如何 return [=44] 中的所有内容=]s,我找不到要删除的信息。

如果您在 IntervalDesigns 实体中定义 ForeignKey,则可以使用 onDelete = ForeignKey.CASCADE。这将在删除 parent 时传播 children 的删除,并且所有操作都在同一事务中完成(因此在任何一个查询中都不需要 @Transaction)。

你的代码应该是这样的:-

@Entity(
    foreignKeys = {
        @ForeignKey(entity = TimerDesign.class,
        parentColumns = "timer_design_id",
        childColumns = "parent_timer_id",
        onDelete = ForeignKey.CASCADE)
    },
    indices = {@Index("parent_timer_id")})

public class IntervalDesign {
    ... rest of the class/entity code
}
  • 请注意已添加索引,否则 Room 会发出警告。
  • Room 可能会在您下次构建应用程序时坚持更新数据库架构版本号。

备选(不推荐)

一个替代方案,尽管有点笨拙,但会定义 Dao 以删除每个(children 由 parent_id 和 parent 由它的 id)并有一个静态方法在删除 children 和 parent

的 parent 实体 (Timer_Design) 中
  • 这是正确的方法,如果定义了外键以确保引用完整性,但没有定义 onDelete 操作,则尝试删除 parent 将导致外键冲突并失败。

所以你可以:-

@Query("DELETE FROM intervaldesign WHERE parent_timer_id=:parent_id")
int deleteItervalDesignChild(int parent_id);
@Query("DELETE FROM parent WHERE timer_design_id=:parent_id")
int deleteParent(int parent_id);
  • 请注意,您的 @Query("DELETE FROM parent WHERE parent_id = :id") 似乎不正确,因为 parent_id 似乎是间隔设计 table 中的一列(如果这是它的名称)。 以上假设 child table 被命名为 intervaldesign.

并且在 TimerDesign class 中,您可以:-

public static void deleteParentAndChildren(TheDatabase db, int parent_id) {
    db.runInTransaction(new Runnable() {
        @Override
        public void run() {
            db.getAllDao().deleteItervalDesignChild(parent_id);
            db.getAllDao().deleteParent(parent_id);
        }
    });
}
  • TheDatabase 将更改为您的 Room 数据库 class。
  • 以上仅针对单个 parent (Timer_Design)。对于所有 parent,你可以有额外的 DAO 来适应。