Android Room FOREIGN KEY 约束失败 [英] Android Room FOREIGN KEY constraint failed

查看:25
本文介绍了Android Room FOREIGN KEY 约束失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试借助 Google 在 I/O 2017 中引入的 Android Room Persistence(一种 ORM)在 Android SQLite 中设计和实现文件夹树结构.在我的设计中,一个文件夹可以包含另一个文件夹和文件.这是我的文件夹和文件代码:

I'm trying to design and implement a folder tree structure in Android SQLite with help of Android Room Persistence (an ORM) which Google introduced in I/O 2017. In my design, a folder can contain another folders and files. Here are my codes for folder and file:

文件模型:

@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 列上为父级提供外键.

Which have a foreign key on ID column of it self for parent.

这里是 FolderDAO:

and here is 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);
}

但是当我创建一个文件夹对象并尝试插入它时:

But when I make a folder object and try to insert it:

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

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

        }
    });

得到这个错误:

外键约束失败

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

有谁知道我的项目表出了什么问题或建议另一种设计?

Does anyone know what's wrong or suggest another design for my project table?

推荐答案

我让它工作了,但没有使用 int 主键.我不是那种 ORM 场景的忠实粉丝,只是因为这些问题.

I got this to work, but not using int primary keys. I'm not a huge fan of those for this sort of ORM scenario, just because of these sorts of problems.

因此,这是一个使用 UUID 作为其主键的自引用 Category 类:

So, here's a self-referential Category class that uses a UUID for its primary key:

/***
 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 方法,例如:

Now you can have DAO methods like:

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

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

这篇关于Android Room FOREIGN KEY 约束失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆