2017-06-19 43 views
6

Tôi đang cố gắng thiết kế và triển khai cấu trúc cây thư mục trong Android SQLite với sự trợ giúp của Android Room Persistence (một ORM) mà Google đã giới thiệu trong I/O 2017. Trong thiết kế của tôi, một thư mục có thể chứa một thư mục và tệp khác. Dưới đây là mã của tôi cho thư mục và tập tin:Android Room NGOÀI KEY ràng buộc không thành công

file mẫu:

@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 
} 

Và đây là thư mục 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; 
} 

nào có một khoá ngoại trên cột ID của nó tự cho mẹ .

và đây là 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); 
} 

Nhưng khi tôi thực hiện một đối tượng thư mục và cố gắng chèn nó:

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

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

     } 
    }); 

nhận được lỗi này:

NƯỚC NGOÀI chế KEY thất bại

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

D oes bất cứ ai biết những gì sai hoặc đề xuất một thiết kế cho bảng dự án của tôi?

+0

"Tôi làm cho một đối tượng thư mục và cố gắng chèn nó "- hãy chỉnh sửa câu hỏi của bạn và đăng mã này, cùng với dấu vết ngăn xếp Java hoàn chỉnh. – CommonsWare

+0

@CommonsWare Edited. –

+0

Bạn chưa chỉ định thư mục gốc và dự đoán của tôi là điều đang kích hoạt lỗi này. Tất nhiên, bạn * không thể * chỉ định một thư mục cha cho thư mục đầu tiên, vì không có cha mẹ trỏ đến. [Các khóa ngoài tự tham chiếu hoạt động trong SQLite] (https://stackoverflow.com/q/15967146/115145), mặc dù có vẻ như [bạn cần sử dụng 'NULL' một cách rõ ràng cho giá trị khi thiếu] (https: //stackoverflow.com/a/6518551/115145). Tôi không biết Room tạo ra gì cho câu lệnh 'INSERT' ở đây. – CommonsWare

Trả lời

3

Tôi đã làm việc này nhưng không sử dụng int khóa chính. Tôi không phải là một fan hâm mộ lớn của những người cho loại kịch bản ORM, chỉ vì những loại vấn đề.

Vì vậy, đây là một tự tham chiếu Category lớp có sử dụng một UUID cho khóa chính của nó:

/*** 
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", 
    [email protected](
    entity=Category.class, 
    parentColumns="id", 
    childColumns="parentId", 
    onDelete=CASCADE), 
    [email protected](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; 
    } 
} 

Bây giờ bạn có thể có phương pháp DAO như:

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

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

Điều này thật tuyệt, tôi đã sử dụng mã của bạn để triển khai cấu trúc thư mục và giờ đây nó hoạt động như một sự quyến rũ. Nhưng bạn có biết vấn đề với mã của tôi không? –

+1

@HamidrezaSahraei: Sự khác biệt đáng kể duy nhất là bạn đang sử dụng các khóa 'int' được tạo tự động, và tôi thì không. Bạn có thể thử chuyển sang 'Integer' và xem liệu giá trị mặc định' null' có hoạt động tốt hơn không. Tôi đoán là '0' mặc định' int' đã phá vỡ ràng buộc khóa ngoại, vì Room không thể nói rằng '0' có nghĩa là" không có quan hệ ".Nhưng, đó chỉ là một phỏng đoán. – CommonsWare

+0

Bạn có thể tạo kiểu khóa ngoài Integer, có thể null. Và giữ nguyên loại id của bạn – Yushi

Các vấn đề liên quan