簡體   English   中英

Android Room FOREIGN KEY約束失敗

[英]Android Room FOREIGN KEY constraint failed

我試圖在Android SQLite中設計和實現文件夾樹結構,借助Google在I / O 2017中引入的Android Room Persistence(一種ORM)。在我的設計中,文件夾可以包含其他文件夾和文件。 這是我的文件夾和文件的代碼:

文件模型:

@Entity(tableName = "files", foreignKeys = @ForeignKey(entity = Folder.class,
    parentColumns = "id",
    childColumns = "parent_id",
    onDelete = CASCADE))
public class File {
    @PrimaryKey(autoGenerate = true)
    private int id;

    private String title;
    private Date creationDate;

    @ColumnInfo(name = "parent_id")
    public int parentId;

    //here setters and getters skipped but exist in original code
}

這是文件夾代碼:

@Entity(tableName = "folders", foreignKeys = @ForeignKey(entity = Folder.class,
    parentColumns = "id",
    childColumns = "parent_id",
    onDelete = CASCADE,onUpdate = SET_NULL))
public class Folder {
    @PrimaryKey(autoGenerate = true)
    private int id;

    private String name;

    @ColumnInfo(name = "parent_id")
    private int parentId;
}

父ID的ID列上有一個外鍵。

這里是FolderDAO:

@Dao
public interface FolderDAO {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public void insertFolder(Folder... folders);

    @Update
    public void updateFolder(Folder... folders);


    @Delete
    public void deleteFolders(Folder... folders);

    @Query("SELECT * FROM folders")
    List<Folder> getAll();

    @Query("SELECT * FROM folders WHERE id IN (:folderIds)")
    List<Folder> loadAllByIds(int[] folderIds);
}

但是當我創建一個文件夾對象並嘗試插入它時:

AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            Folder folder = new Folder();
            folder.setName("All");

            DatabaseInstance.getInstance(getApplicationContext()).folderDAO().insertFolder(folder);

        }
    });

得到這個錯誤:

FOREIGN KEY約束失敗

         --------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
              Process: sahraei.hamidreza.com.note, PID: 1835
              android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787)
                  at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
                  at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:782)
                  at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
                  at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
                  at android.arch.persistence.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:80)
                  at android.arch.persistence.room.EntityInsertionAdapter.insert(EntityInsertionAdapter.java:80)
                  at sahraei.hamidreza.com.note.DAO.FolderDAO_Impl.insertFolder(FolderDAO_Impl.java:80)
                  at sahraei.hamidreza.com.note.ItemListActivity$1.run(ItemListActivity.java:62)
                  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                  at java.lang.Thread.run(Thread.java:818)

有誰知道什么是錯的或建議我的項目表的另一個設計?

我得到了這個工作,但沒有使用int主鍵。 我不是那種ORM場景的忠實粉絲,只是因為這些問題。

所以,這是一個自引用的Category類,它使用UUID作為其主鍵:

/***
 Copyright (c) 2017 CommonsWare, LLC
 Licensed under the Apache License, Version 2.0 (the "License"); you may not
 use this file except in compliance with the License. You may obtain  a copy
 of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
 by applicable law or agreed to in writing, software distributed under the
 License is distributed on an "AS IS" BASIS,  WITHOUT WARRANTIES OR CONDITIONS
 OF ANY KIND, either express or implied. See the License for the specific
 language governing permissions and limitations under the License.
 */

package com.commonsware.android.room.dao;

import android.arch.persistence.room.Entity;
import android.arch.persistence.room.ForeignKey;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.Index;
import android.arch.persistence.room.PrimaryKey;
import java.util.UUID;
import static android.arch.persistence.room.ForeignKey.CASCADE;

@Entity(
  tableName="categories",
  foreignKeys=@ForeignKey(
    entity=Category.class,
    parentColumns="id",
    childColumns="parentId",
    onDelete=CASCADE),
  indices=@Index(value="parentId"))
public class Category {
  @PrimaryKey
  public final String id;
  public final String title;
  public final String parentId;

  @Ignore
  public Category(String title) {
    this(title, null);
  }

  @Ignore
  public Category(String title, String parentId) {
    this(UUID.randomUUID().toString(), title, parentId);
  }

  public Category(String id, String title, String parentId) {
    this.id=id;
    this.title=title;
    this.parentId=parentId;
  }
}

現在你可以使用DAO方法:

@Query("SELECT * FROM categories WHERE parentId IS NULL")
Category findRootCategory();

@Query("SELECT * FROM categories WHERE parentId=:parentId")
List<Category> findChildCategories(String parentId);

我花了很長時間才發現擁有一個自動生成的主鍵的parentColumns元素似乎根本不被允許,即使它是使用具有默認值的Kotlin數據類的uuid,如下所示:

MyClass{
    //Don't do this
    @PrimaryKey(autoGenerate = true)
    var uuid: String = UUID.randomUUID()
}

始終確保您直接指定父列。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM