GoogleがI/Oで導入したAndroid Room Persistence(ORM)の助けを借りて、Android SQLiteでフォルダーツリー構造を設計および実装しようとしています。 2017.私のデザインでは、フォルダーに別のフォルダーとファイルを含めることができます。
ファイルモデル:
@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列に外部キーがあります。
ここに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);
}
});
このエラーを取得:
外部キー制約が失敗しました
--------- 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()
}
親列が直接指定されていることを常に確認してください。