简体   繁体   中英

Android Room - Foreign Key constraint failed (code 787) error

I am new to Android development and I'm trying to create a Trip which has many Locations in it. A trip is created, then accessed and a Location is created by using the trip_id passed from the previous activity. I'm using LiveData to store the List of data and display them in a RecyclerView.

I have tried many of the solutions posted here, such as using UUID for the primary keys instead of auto-generating them: Android Room FOREIGN KEY constraint failed .

However, I still get the same error. So this is the original code, without UUID.

Trip.java

@Entity(tableName = "trip_table",
        indices = {@Index(value = {"location_Id"}, unique = true),
                @Index(value = {"tripNo"}, unique = true)})

public class Trip {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo (name = "location_Id")
    private int id;

    private String title;

    private String description;

    private int priority;

    private int tripNo;

    public Trip(String title, String description, int priority) {
        this.title = title;
        this.description = description;
        this.priority = priority;
    }
// getter, setters

Location.java

@Entity(tableName = "location_table",
        foreignKeys = @ForeignKey(entity = Trip.class, parentColumns = "tripNo", childColumns = "trip_Id"),
        indices = {@Index(value = {"trip_Id"})})

public class Location {

    @PrimaryKey(autoGenerate = true)
    private int locationId;

    @ColumnInfo (name = "trip_Id")
    private int tripId;

    private String locationName;

    @TypeConverters(LatLngConverter.class)
    private LatLng latLng;

    public Location(int tripId, String locationName, LatLng latLng) {
        this.tripId = tripId;
        this.locationName = locationName;
        this.latLng = latLng;
    }
// getter, setters

Creating a new Trip in MainActivity.java.

Trip trip = new Trip(title, description, priority);
tripViewModel.insert(trip);
tripViewModel.updateTripNo();

Passing trip_id to the next activity

public void onTripItemClick(Trip trip) {
Intent intent = new Intent(MainActivity.this, viewTripLocations.class);
intent.putExtra(viewTripLocations.EXTRA_TRIP_ID, trip.getId());
Log.d("TRIPINFO", "Trip ID is " + trip.getId()); // D/TRIPINFO: Trip ID is 2
Log.d("TRIPINFO", "Trip No is " + trip.getTripNo()); // D/TRIPINFO: Trip No is 2
startActivity(intent);
}

This works fine and it shows up on the RecyclerView, allowing me to click on it to go into the next activity: viewTripLocations.java.

After entering a name and LatLng coordinates in another activity, the onActivityResult method is triggered and returns to viewTripLocations.java.

protected void onActivityResult(int requestCode, int resultCode, Intent data)
// codes getting name, latlng

Intent intent = getIntent();
Bundle bundle = intent.getExtras();
int tripId = ((int)(bundle.get(EXTRA_TRIP_ID)));
Location location = new Location(tripId, locationName, locationLatLng);

Log.d("Trip ID is ", "" +tripId); //D/Trip ID used is: 2
Log.d("LOCINFO","Location is " + location.getLocationName() + " ID is " + location.getLocationId() + " REFERENCES Trip " + location.getTripId()); // D/LOCINFO: Location is v ID is 0 REFERENCES Trip 2

locationViewModel.insert(location); //crashes here

This is the error outputted

D/Trip ID is : 1
D/TRIPINFO: Trip is 23/11/2019 ID is 1
D/LOCINFO: Location is Tokyo ID is 0 REFERENCES Trip 1
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #3
    Process: com.example.TravelPlanner, PID: 9117
    java.lang.RuntimeException: An error occurred while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:354)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
        at java.util.concurrent.FutureTask.run(FutureTask.java:271)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
        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:764)
     Caused by: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY[787])
        at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:995)
        at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
        at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
        at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:51)
        at androidx.room.EntityInsertionAdapter.insert(EntityInsertionAdapter.java:64)
        at com.example.travelplanner.LocationDao_Impl.insert(LocationDao_Impl.java:110)
        at com.example.travelplanner.LocationRepository$InsertLocationAsyncTask.doInBackground(LocationRepository.java:51)
        at com.example.travelplanner.LocationRepository$InsertLocationAsyncTask.doInBackground(LocationRepository.java:42)
        at android.os.AsyncTask$2.call(AsyncTask.java:333)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
        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:764) 

To add on, using DB Browser allowed me to confirm the insertion of Trip using tripViewModel.insert(trip).

I understand why the error happens but do not understand how as a Trip object is created beforehand

As I'm still inexperienced, I might be doing some things wrong so I would appreciate the help.

When you're inserting the location object into the database, the foreign key associated with it is not available in the parent table ie your Trip table, You need to debug this line and it's previous calls

int tripId = ((int)(bundle.get(EXTRA_TRIP_ID))); // Whether the ID return by this line is exist in the database or not, it it does then pass it into the location constructor.

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