我有以下实体:
@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);
我看到的选项及其问题:
我有一个地址列表,其中一个是“默认”。删除地址时,我希望驻留在已删除地址上的“人类”“移动”到“默认”。 我用过:
@Query("delete from Address where address = :address")
void deleteAddress(String address);
所以onDelete = SET_DEFAULT似乎不像我想象的那样,如果我将默认值设置为人类实体中的地址。
此操作当前失败,并显示: NOT NULL约束失败。
删除操作的替代方法是编辑地址并将其设置为“默认”,然后与现有的“默认”条目合并。 我尝试过:
@Query("update Address SET address = :address WHERE address = :addressToEdit")
void editAddress(String addressToEdit, String newAddress);
此操作当前失败,并显示:唯一约束失败。,因为显然已经有一个具有相同名称的地址。
在两个实体中都将地址设置为@Nullable。这样,“默认”地址为空。这给我的解决方案增加了额外的复杂性(不希望使用它),而且似乎无法使用以下代码使用空地址查询人类,因为它不返回任何内容。
@Query("select * from Human where address = :address")
LiveData<List<Human>> getHumans(String address);
如何将此设置恢复为默认的已删除地址(外键)?
答案 0 :(得分:0)
我建议修改您的地址实体,并将id字段添加为自动递增的整数。然后在人类实体中,您可以通过id字段引用地址。因此,在删除地址记录之前,您可以使用默认参考ID更新您要删除的参考的人员记录,例如:1然后可以通过其ID删除该地址记录。在这里您可以解决地址唯一约束问题。
答案 1 :(得分:0)
到目前为止,目前可行的最佳解决方案是使用问题中的第三个选项:
@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;
}
答案 2 :(得分:0)
当前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();
AddressDao:
@Update
void updateAddresses(Address... addresses);
AsyncTask类
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;
}