简体   繁体   中英

Android studio and Room - Foreign keys and constraint failed

I'm trying to make an app with Room database. I have one table Bird and one table Family. (One-to-many relationship).

@Entity(tableName ="bird",
        foreignKeys =
        @ForeignKey(entity = Family.class,
        parentColumns = "id",
        childColumns = "familyId",
        onDelete = CASCADE),
        indices = {@Index("familyId")})


public class Bird {

    @PrimaryKey(autoGenerate = true)
    private int id;
    private int familyId;
    private String name;
    private String family;
    private String description;
    private String biology;

    public Bird(@NonNull String name, @NonNull String family, String description, String biology){
        this.name = name;
        this.family = family;
        this.description= description;
        this.biology = biology;
        this.familyId = familyId;
    }
@Entity(tableName = "family")
public class Family {

    @PrimaryKey(autoGenerate = true)
    private int id;
    private String family;

    public Family(@NonNull String family)
    {
        this.family = family;
    }

Everytime I try to run my list of bird (which worked fine before implementing the family entity), nothing shows up and when I try to add a new bird with an @Insert query, I get hit by this :

Caused by: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
        at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:879)
        at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:790)
        at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:88)
        at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:51)
        at androidx.room.EntityInsertionAdapter.insert(EntityInsertionAdapter.java:64)
        at com.example.room.Dao_Impl.insertBird(Dao_Impl.java:115)
        at com.example.room.BirdRepository$InsertBirdAsyncTask.doInBackground(BirdRepository.java:56)
        at com.example.room.BirdRepository$InsertBirdAsyncTask.doInBackground(BirdRepository.java:45)
        at android.os.AsyncTask$3.call(AsyncTask.java:378)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:919)

Do you guys have any idea from where that could come from ?

Also am I filling the database right that way ?

private static void fillWithSartingData(Context context){
    Dao dao = getInstance(context).dao();
    FamilyDao familyDao = getInstance(context).familyDao();

    JSONArray birds = loadJSONArray(context);
    JSONArray families = loadJSONArray(context);

    try{

        for(int i = 0; i< families.length(); i++){
            JSONObject familyObj = families.getJSONObject(i);

            String family = familyObj.getString("FamilieF");
            familyDao.insertFamily(new Family(family));
        }


        for(int i = 0; i< birds.length(); i++){
            JSONObject bird = birds.getJSONObject(i);
            String engName = bird.getString("NameEng");
            String family = bird.getString("FamilieF");
            String description = bird.getString("Description");
            String biology = bird.getString("Biologie");

            dao.insertBird(new Bird(engName, family, description, biology));

        }

    } catch (JSONException e){

    }
}

Thank you! Alex

You have violated foreign key constraint "FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)" because you did not set familyId in Bird class

you have to set the familyId in Bird class before inserting bird

to do that add a familyId argument to bird constructor like this:

public Bird(@NonNull String name, @NonNull String family, String description, String biology, long familyId){
        this.name = name;
        this.family = family;
        this.description= description;
        this.biology = biology;
        this.familyId = familyId;
    }

insertFamily in familyDao should return Long (if it has one Family argument) or Long Array (if it has vararg Family argument) then you get id of inserted family from insertFamily and use it as familyId like this:

for(int i = 0; i< families.length(); i++){
       JSONObject familyObj = families.getJSONObject(i);
       String family = familyObj.getString("FamilieF");
       long familyId = familyDao.insertFamily(new Family(family));// get familyId


       for(int i = 0; i< birds.length(); i++){
            JSONObject bird = birds.getJSONObject(i);
            String engName = bird.getString("NameEng");
            String family = bird.getString("FamilieF");
            String description = bird.getString("Description");
            String biology = bird.getString("Biologie");
            dao.insertBird(new Bird(engName, family, description, biology, familyId));// use familyId
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM