Android Room-外键约束失败(代码787)错误

时间:2019-11-04 18:27:03

标签: android sqlite orm android-room android-orm

我是Android开发的新手,我正在尝试创建一个Trip,其中包含多个位置。使用从上一个活动传递的trip_id,创建一个旅程,然后对其进行访问并创建一个位置。我正在使用LiveData存储数据列表,并将其显示在RecyclerView中。

我已经尝试过这里发布的许多解决方案,例如使用UUID作为主键而不是自动生成它们:Android Room FOREIGN KEY constraint failed

但是,我仍然遇到相同的错误。这是原始代码,没有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

在MainActivity.java中创建一个新的Trip。

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

将trip_id传递到下一个活动

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);
}

这工作正常,并显示在RecyclerView上,允许我单击它进入下一个活动:viewTripLocations.java。

在另一个活动中输入名称和LatLng坐标后,将触发onActivityResult方法,并返回到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

这是输出的错误

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) 

作为补充,使用数据库浏览器允许我使用tripViewModel.insert(trip)确认Trip的插入。

我了解为什么会发生错误,但不了解如何预先创建Trip对象

由于我仍然没有经验,所以我可能做错了一些事情,所以我将不胜感激。

1 个答案:

答案 0 :(得分:0)

将位置对象插入数据库时​​,与其关联的外键在父表(即Trip表)中不可用,您需要调试该行及其之前的调用

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.