Android 房间外键 on_Delete = 级联无效
Android Room Foreign Key onDelte = Cascade has no effect
我在两个 table 之间有一个一对多的关系。父table是"People",子table是"Pets"。一个人可以养很多只宠物。一个宠物只能有一个人。
我使用@Relation 在PersonWithPets.java 中创建两个table 之间的关系。在 Pets.java 中,我将 ForeignKey 与 onDelete = CASCADE 一起使用。但是如果我删除一个人,相应的宠物会留在数据库中,我想不通为什么。我几乎好像 onDelte = CASCADE 没有效果。
也许我没有使用正确的 id,但我已经经历了很多次,似乎无法弄清楚为什么一个人的宠物没有被删除。
当然,我可以使用宠物的 personId 来迭代和删除共享同一 personId 的所有宠物,但这似乎违背了 @ForeignKey 注释的目的。
我可能遗漏了什么?
对不起,如果这是显而易见的。我是 Android.
的新手
Person.java
@Entity(tableName = "person")
public class Person {
@PrimaryKey(autoGenerate = true)
private Integer id;
String name;
@Ignore
private List<Pet> pets = null;
public Person(){
// empty constructor for serialization
}
@Ignore
public Person(String name, List<Pet> pets) {
this.name = name;
this.pets = pets;
}
public Person(PersonWithPets personWithPets) {
this.id = personWithPets.getPerson().getId();
this.name = personWithPets.getPerson().getName();
this.pets = this.getPets(personWithPets);
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setPet(Pet pet) {
if (this.pets == null) {
this.pets = new ArrayList<>();
}
this.pets.add(pet);
}
public List<Pet> getPets() {
return this.pets;
}
private List<Pet> getPets(PersonWithPets personWithPets) {
return personWithPets.getPets();
}
public void setName(String name) {
this.name = name;
}
}
Pet.java
@Entity(tableName = "pet")
public class Pet {
@PrimaryKey(autoGenerate = true)
private Integer id;
String name;
public Pet() {
}
/**
* @param name
*/
@Ignore
public Pet(String name) {
this.name = name;
}
@ForeignKey
(entity = Person.class,
parentColumns = "id",
childColumns = "personId",
onDelete = CASCADE,
onUpdate = CASCADE)
private Integer personId;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPersonId() {
return personId;
}
public void setPersonId(Integer personId) {
this.personId = personId;
}
}
PersonWithPets.java
public class PersonWithPets {
@Embedded public Person person;
@Relation(
parentColumn = "id",
entityColumn = "personId",
entity = Pet.class
)
public List<Pet> pets;
public Person getPerson() {
return person;
}
public List<Pet> getPets() {
return pets;
}
}
PersonRepository
public class PersonRepository {
private static final String TAG = "RecipeRepository";
private PersonDao personDao;
private LiveData<List<Person>> people;
private LiveData<List<PersonWithPets>> peopleWithPets;
private LiveData<List<Pet>> pets;
public PersonRepository (Application application) {
PersonDatabase db = PersonDatabase.getInstance(application);
personDao = db.personDao();
people = personDao.getAllPeople();
peopleWithPets = personDao.getAllPeopleWithPets();
pets = personDao.getAllPets();
}
// Get all people with pets
public LiveData<List<PersonWithPets>> getAllPeopleWithPets() {
return peopleWithPets;
}
// Delete
public void delete(Person person) {
new DeletePersonAsyncTask(personDao).execute(person);
}
// Delete All People
private static class DeleteAllPeopleAsyncTask extends AsyncTask<Void, Void, Void> {
private PersonDao personDao;
private DeleteAllPeopleAsyncTask(PersonDao personDao) {
this.personDao = personDao;
}
@Override
protected Void doInBackground(Void... voids) {
personDao.deleteAllPeople();
//personDao.deleteAllPets();
return null;
}
}
}
数据库
@Database(entities = {Person.class, Pet.class}, version = 5, exportSchema = false)
public abstract class PersonDatabase extends RoomDatabase {
private static final String TAG = "PersonDatabase";
private static PersonDatabase instance;
public abstract PersonDao personDao();
public static synchronized PersonDatabase getInstance(Context context) {
if(instance == null){
instance = Room.databaseBuilder(context.getApplicationContext(),
PersonDatabase.class, "person_database")
.fallbackToDestructiveMigration()
.addCallback(roomCallback)
.build();
}
return instance;
}
private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback(){
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
new PopulateDbAsyncTask(instance).execute();
}
};
private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void> {
private PersonDao personDao;
private PopulateDbAsyncTask(PersonDatabase db){
personDao = db.personDao();
}
@Override
protected Void doInBackground(Void... voids) {
Person adam = new Person();
adam.setName("Adam");
Pet dog = new Pet();
dog.setName("Dog");
adam.setPet(dog);
Long personId = personDao.insertPerson(adam);
for (Pet pet : adam.getPets()) {
pet.setPersonId(personId.intValue());
personDao.insertPet(pet);
}
return null;
}
}
}
DAO
@Dao
public interface PersonDao {
@Transaction
@Insert
Long insertPerson(Person person);
@Transaction
@Insert
void insertPet(Pet pet);
@Transaction
@Update
int updatePerson(Person person);
@Transaction
@Delete
void deletePerson(Person person);
@Transaction
@Query("DELETE FROM person")
void deleteAllPeople();
@Transaction
@Query("DELETE FROM pet")
void deleteAllPets();
@Transaction
@Query("SELECT * FROM person")
LiveData<List<Person>> getAllPeople();
@Transaction
@Query("SELECT * FROM person")
LiveData<List<PersonWithPets>> getAllPeopleWithPets();
@Transaction
@Query("SELECT * FROM pet")
LiveData<List<Pet>> getAllPets();
}
MainActivity
viewModel.getAllPeopleWithPets().observe(this, new Observer<List<PersonWithPets>>() {
@Override
public void onChanged(@Nullable List<PersonWithPets> peopleWithPets) {
Log.d(TAG, "onChanged: --------------------------------");
Log.d(TAG, "onChanged: ALL PEOPLE WITH PETS");
for (PersonWithPets personWithPets : peopleWithPets) {
Log.d(TAG, "onChanged: Name: " + personWithPets.getPerson().getName() + " ID: " + personWithPets.getPerson().getId());
Log.d(TAG, "onChanged: Pets: " + + personWithPets.getPets().size());
if (personWithPets.getPets().size() > 0) {
for (Pet pet : personWithPets.getPets()) {
Log.d(TAG, "onChanged: Name: " + pet.getName() + " ID: " + pet.getId() + " PersonID: " + pet.getPersonId());
}
} else {
Log.d(TAG, "onChanged: No pets.");
}
}
Log.d(TAG, "onChanged: --------------------------------");
setTitle("People: " + peopleWithPets.size() + " Pets: " + viewModel.getAllPets().getValue().size());
}
});
尝试从字段声明中删除外键注释到实体的顶部:
@Entity(tableName = "pet", foreignKeys = @ForeignKey
(entity = Person.class,
parentColumns = "id",
childColumns = "personId",
onDelete = CASCADE,
onUpdate = CASCADE))
public class Pet {
@PrimaryKey(autoGenerate = true)
private Integer id;
.......................
字段上方的@ForeignKey 似乎对创建外键没有任何影响。您可以在自动生成的数据库 Java class 中看到它,也可以使用任何 SQLite 浏览器检查 table 的结构。
我在两个 table 之间有一个一对多的关系。父table是"People",子table是"Pets"。一个人可以养很多只宠物。一个宠物只能有一个人。
我使用@Relation 在PersonWithPets.java 中创建两个table 之间的关系。在 Pets.java 中,我将 ForeignKey 与 onDelete = CASCADE 一起使用。但是如果我删除一个人,相应的宠物会留在数据库中,我想不通为什么。我几乎好像 onDelte = CASCADE 没有效果。 也许我没有使用正确的 id,但我已经经历了很多次,似乎无法弄清楚为什么一个人的宠物没有被删除。
当然,我可以使用宠物的 personId 来迭代和删除共享同一 personId 的所有宠物,但这似乎违背了 @ForeignKey 注释的目的。
我可能遗漏了什么? 对不起,如果这是显而易见的。我是 Android.
的新手Person.java
@Entity(tableName = "person")
public class Person {
@PrimaryKey(autoGenerate = true)
private Integer id;
String name;
@Ignore
private List<Pet> pets = null;
public Person(){
// empty constructor for serialization
}
@Ignore
public Person(String name, List<Pet> pets) {
this.name = name;
this.pets = pets;
}
public Person(PersonWithPets personWithPets) {
this.id = personWithPets.getPerson().getId();
this.name = personWithPets.getPerson().getName();
this.pets = this.getPets(personWithPets);
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setPet(Pet pet) {
if (this.pets == null) {
this.pets = new ArrayList<>();
}
this.pets.add(pet);
}
public List<Pet> getPets() {
return this.pets;
}
private List<Pet> getPets(PersonWithPets personWithPets) {
return personWithPets.getPets();
}
public void setName(String name) {
this.name = name;
}
}
Pet.java
@Entity(tableName = "pet")
public class Pet {
@PrimaryKey(autoGenerate = true)
private Integer id;
String name;
public Pet() {
}
/**
* @param name
*/
@Ignore
public Pet(String name) {
this.name = name;
}
@ForeignKey
(entity = Person.class,
parentColumns = "id",
childColumns = "personId",
onDelete = CASCADE,
onUpdate = CASCADE)
private Integer personId;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPersonId() {
return personId;
}
public void setPersonId(Integer personId) {
this.personId = personId;
}
}
PersonWithPets.java
public class PersonWithPets {
@Embedded public Person person;
@Relation(
parentColumn = "id",
entityColumn = "personId",
entity = Pet.class
)
public List<Pet> pets;
public Person getPerson() {
return person;
}
public List<Pet> getPets() {
return pets;
}
}
PersonRepository
public class PersonRepository {
private static final String TAG = "RecipeRepository";
private PersonDao personDao;
private LiveData<List<Person>> people;
private LiveData<List<PersonWithPets>> peopleWithPets;
private LiveData<List<Pet>> pets;
public PersonRepository (Application application) {
PersonDatabase db = PersonDatabase.getInstance(application);
personDao = db.personDao();
people = personDao.getAllPeople();
peopleWithPets = personDao.getAllPeopleWithPets();
pets = personDao.getAllPets();
}
// Get all people with pets
public LiveData<List<PersonWithPets>> getAllPeopleWithPets() {
return peopleWithPets;
}
// Delete
public void delete(Person person) {
new DeletePersonAsyncTask(personDao).execute(person);
}
// Delete All People
private static class DeleteAllPeopleAsyncTask extends AsyncTask<Void, Void, Void> {
private PersonDao personDao;
private DeleteAllPeopleAsyncTask(PersonDao personDao) {
this.personDao = personDao;
}
@Override
protected Void doInBackground(Void... voids) {
personDao.deleteAllPeople();
//personDao.deleteAllPets();
return null;
}
}
}
数据库
@Database(entities = {Person.class, Pet.class}, version = 5, exportSchema = false)
public abstract class PersonDatabase extends RoomDatabase {
private static final String TAG = "PersonDatabase";
private static PersonDatabase instance;
public abstract PersonDao personDao();
public static synchronized PersonDatabase getInstance(Context context) {
if(instance == null){
instance = Room.databaseBuilder(context.getApplicationContext(),
PersonDatabase.class, "person_database")
.fallbackToDestructiveMigration()
.addCallback(roomCallback)
.build();
}
return instance;
}
private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback(){
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
new PopulateDbAsyncTask(instance).execute();
}
};
private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void> {
private PersonDao personDao;
private PopulateDbAsyncTask(PersonDatabase db){
personDao = db.personDao();
}
@Override
protected Void doInBackground(Void... voids) {
Person adam = new Person();
adam.setName("Adam");
Pet dog = new Pet();
dog.setName("Dog");
adam.setPet(dog);
Long personId = personDao.insertPerson(adam);
for (Pet pet : adam.getPets()) {
pet.setPersonId(personId.intValue());
personDao.insertPet(pet);
}
return null;
}
}
}
DAO
@Dao
public interface PersonDao {
@Transaction
@Insert
Long insertPerson(Person person);
@Transaction
@Insert
void insertPet(Pet pet);
@Transaction
@Update
int updatePerson(Person person);
@Transaction
@Delete
void deletePerson(Person person);
@Transaction
@Query("DELETE FROM person")
void deleteAllPeople();
@Transaction
@Query("DELETE FROM pet")
void deleteAllPets();
@Transaction
@Query("SELECT * FROM person")
LiveData<List<Person>> getAllPeople();
@Transaction
@Query("SELECT * FROM person")
LiveData<List<PersonWithPets>> getAllPeopleWithPets();
@Transaction
@Query("SELECT * FROM pet")
LiveData<List<Pet>> getAllPets();
}
MainActivity
viewModel.getAllPeopleWithPets().observe(this, new Observer<List<PersonWithPets>>() {
@Override
public void onChanged(@Nullable List<PersonWithPets> peopleWithPets) {
Log.d(TAG, "onChanged: --------------------------------");
Log.d(TAG, "onChanged: ALL PEOPLE WITH PETS");
for (PersonWithPets personWithPets : peopleWithPets) {
Log.d(TAG, "onChanged: Name: " + personWithPets.getPerson().getName() + " ID: " + personWithPets.getPerson().getId());
Log.d(TAG, "onChanged: Pets: " + + personWithPets.getPets().size());
if (personWithPets.getPets().size() > 0) {
for (Pet pet : personWithPets.getPets()) {
Log.d(TAG, "onChanged: Name: " + pet.getName() + " ID: " + pet.getId() + " PersonID: " + pet.getPersonId());
}
} else {
Log.d(TAG, "onChanged: No pets.");
}
}
Log.d(TAG, "onChanged: --------------------------------");
setTitle("People: " + peopleWithPets.size() + " Pets: " + viewModel.getAllPets().getValue().size());
}
});
尝试从字段声明中删除外键注释到实体的顶部:
@Entity(tableName = "pet", foreignKeys = @ForeignKey
(entity = Person.class,
parentColumns = "id",
childColumns = "personId",
onDelete = CASCADE,
onUpdate = CASCADE))
public class Pet {
@PrimaryKey(autoGenerate = true)
private Integer id;
.......................
字段上方的@ForeignKey 似乎对创建外键没有任何影响。您可以在自动生成的数据库 Java class 中看到它,也可以使用任何 SQLite 浏览器检查 table 的结构。