房间:删除外键或将外键设置为默认值



我有以下实体:

@Entity(indices  = {@Index("address")},
foreignKeys = @ForeignKey(
entity = Address.class,
parentColumns = "address",
childColumns = "address",
onUpdate = CASCADE,
onDelete = SET_DEFAULT))
public class Human {
@PrimaryKey(autoGenerate = true)
public long id;
@NonNull
public String name;
@NonNull
public String address;
}
@Entity
public class Address {
@PrimaryKey
@NonNull
public String address;
public int someInt;
}

我添加了具有不同地址的"人类",后来我尝试使用以下方法删除或编辑:

@Insert(onConflict = REPLACE)
void add(Human human);

我看到的选项及其问题:

  1. 我有一个地址列表,其中一个是"默认"地址。当我删除地址时,我希望居住在已删除地址的"人类"移动"为"默认"。 我使用过:

    @Query("delete from Address where address = :address")
    void deleteAddress(String address);
    

等等,如果我在人类实体中将默认值设置为地址,SET_DEFAULT似乎不像我想象的那样工作。

此操作当前失败,并显示:非空约束失败。

  1. 删除的替代方法是编辑地址并将其设置为"默认",从而与现有的"默认"条目合并。 我试过了:

    @Query("update Address SET address = :address WHERE address = :addressToEdit")
    void editAddress(String addressToEdit, String newAddress);
    

此操作当前失败,并显示:唯一约束失败。 因为显然已经有一个同名的地址。

  1. 将地址设置为在两个实体中@Nullable。这样,"默认"地址为空。这为我的解决方案增加了额外的复杂性(不喜欢它(,而且似乎我无法使用以下代码使用空地址查询 Human,因为它不返回任何内容。

    @Query("select * from Human where address = :address")
    LiveData<List<Human>> getHumans(String address);
    

如何将此设置实现为已删除地址(外键(的默认值?

我建议修改您的地址实体并将 ID 字段添加为整数自动递增。 然后在 人类实体 您可以通过 id 字段引用地址。 因此,在删除地址记录之前,您可以更新使用要通过默认引用ID删除的引用的人类记录,例如: 1然后,您可以按其ID删除此地址记录。 在这里您可以解决地址唯一约束问题。

到目前为止,我最好的解决方案是使用问题的第三个选项:

@Query("select * from Human where address is NULL")
LiveData<List<Human>> getAllHumansWithNullAddress();

就像使用 NULL 作为默认值一样。

Address保持不变,但人类变成了:

@Entity(indices  = {@Index("address")},
foreignKeys = @ForeignKey(
entity = Address.class,
parentColumns = "address",
childColumns = "address",
onUpdate = CASCADE,
onDelete = SET_NULL))
public class Human {
@PrimaryKey(autoGenerate = true)
public long id;
@NonNull
public String name;
@Nullable
public String address;
}

目前 Room 不支持 onDelete =SET_DEFAULT 操作,并且 Room 将其视为与 onDelete = SET_NULL 相同,所以我建议如下:-

@Entity(foreignKeys = @ForeignKey(
entity = Address.class,
parentColumns = "address",
childColumns = "fk_address_id",
onUpdate = CASCADE,
onDelete = SET_DEFAULT))
public class Human {
@PrimaryKey(autoGenerate = true)
public long id;
@NonNull
public String name;

@Nullable
public String getFk_address_id() {
return fk_address_id;
}
public void setFk_address_id(@Nullable String fk_address_id) {
this.fk_address_id = fk_address_id;
}
//default address doesn't work on delete as room doesn't support
// on delete set default and treat it like set null
@Nullable
public String fk_address_id = "default address";
public Human(@NonNull String name,  @Nullable String fk_address_id) {
this.name = name;
this.fk_address_id = fk_address_id;
}
}

这是地址实体,其中地址字段是唯一的。

@Entity(indices = {@Index(value = {"address"},
unique = true)})
public class Address {
public void setAddress(@NonNull String address) {
this.address = address;
}
@PrimaryKey(autoGenerate = true)
@NonNull
int id;

public String address = "default address";

public int someInt;
public Address(@NonNull String address, int someInt) {
this.address = address;
this.someInt = someInt;
}
}

在 HumanDao 中,您可以获取空引用地址并将其更新为默认地址。

人类道:

@Query("SELECT * FROM Human where fk_address_id IS NULL")
Human[] getNullRef();

地址道:

@Update
void updateAddresses(Address... addresses);

异步任务类

protected Void doInBackground(Void... voids) {
AppDatabase db = AppDatabase.getDatabase(getApplicationContext());
Address address = db.addressDao().getAddress("address to delete");
if(address != null) {
db.addressDao().delete(address);
Human [] humans = db.humanDao().getNullRef();
for(int i =0; i < humans.length; i++) humans[i].setFk_address_id(DEFAULT_ADDRESS);
db.humanDao().updateHumans(humans);
}
return null;
}

最新更新