【问题标题】:Android Room - deleting from two entities using TransactionsAndroid Room - 使用事务从两个实体中删除
【发布时间】:2021-06-14 20:49:01
【问题描述】:

如何使用事务从 Android 房间的两个表中删除数据?我不能只从一个表中删除数据,要么都删除,要么都不删除。两个实体各有 1 个 DAO。

TimerDesign 是父级,IntervalDesign 是子级

我已经设置了一个父-子类,因为稍后我将需要该类的 1:M 关系来获取每个父级及其所有子级,目前尝试删除一个父级及其所有子级仅从父表中删除.

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;
}

我需要指定父级的 id 以删除它及其所有子级。我知道我的 DAO @Query 没有指定子表,我似乎也无法进行内部连接来解决这个问题。

@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();
}

我可以为Room 1:m 映射类找到的大多数示例和documentation 仅显示如何从两个表中返回所有内容,我找不到任何要删除的信息。

【问题讨论】:

  • 在子实体关系中定义外来父键的地方添加onDelete = ForeignKey.CASCADE

标签: android android-room


【解决方案1】:

如果您在 IntervalDesigns 实体中定义 ForeignKey,则可以使用 onDelete = ForeignKey.CASCADE。这将在删除父级时传播对子级的删除,并且这一切都在同一个事务中完成(因此在任何一个查询中都不需要@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 以删除每个(通过 parent_id 的子级和通过其 id 的父级),并在父实体 (Timer_Design) 中有一个静态方法,该方法先删除子级,然后再删除父级

  • 这是正确的方法,如果定义了 ForeignKey 以确保引用完整性,但没有定义 onDelete 操作,那么尝试删除父项将导致 ForeignKey 冲突并失败。

所以你可以:-

@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 似乎是 intervaldesign 表中的一列(如果这是它的名称)。以上假设子表名为 intervaldesign。

在 TimerDesign 类中,您可以:-

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 数据库类。
  • 以上内容仅适用于单亲 (Timer_Design)。对于所有父母,您都可以有额外的 DAO 来适应。

【讨论】:

  • 非常感谢您花时间回答这个问题 - 您的第一个答案有效。我怎么会忘记好的旧级联!也不需要你说的交易。我还没有检查或尝试过替代答案。
猜你喜欢
  • 2017-11-23
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多