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 的结构。