Создать таблицу с полем иностранной коллекции

У меня есть этот абстрактный класс:

DomainItem

abstract public class DomainItem {

    @DatabaseField(generatedId = true)
    protected long id;

    @ForeignCollectionField(eager = false)
        protected ForeignCollection<ContentItem> contentItens;

    //getters and setters
}

ContentItem:

abstract public class ContentItem {

    @DatabaseField(generatedId = true)
    protected long id;

    @DatabaseField(foreign = true)
    protected DomainItem domainItem;


    @DatabaseField()
    protected String content;

    //getters and setters
}

И эти (не абстрактные):

@DatabaseTable()
public class PhytoterapicItem extends DomainItem{

    public PhytoterapicItem(){

    }

}

PhytoterapicContent

@DatabaseTable(tableName = "phytoterapiccontent")
public class PhytoterapicContent extends ContentItem {

    @DatabaseField(canBeNull = false)
    private String defaultName;

    @DatabaseField(canBeNull = false)
    private String scientificName;

    //getters and setters
}

В моем DatabaseHelper я пытаюсь создать таблицы:

//DatabaseHelper
...
@Override
public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
    try {
        Log.i(TAG, "onCreate");
        TableUtils.createTable(connectionSource, PhytoterapicContent.class);
        Log.i(TAG, "Created table PhytoterapicContent");

        TableUtils.createTable(connectionSource, PhytoterapicItem.class);
        Log.i(TAG, "Created table PhytoterapicItem");
    catch{
       ...
    }

Создается таблица PhytoterapicContent. Но я получил следующую ошибку:

java.sql.SQLException: Внешний класс коллекции br.com.project.model.ContentItem для имени столбца 'contentItens' для поля не содержит поля иностранного класса класса br.com.project.model.PhytoterapicItem

Ответ 1

Итак, сообщение об исключении было разработано для помощи здесь. Чтобы процитировать его с удаленными именами классов:

Класс внешней коллекции ContentItem для поля contentItens имя столбца не содержит чужого поля класса PhytoterapicItem

Это выглядит так. Всякий раз, когда у вас есть ForeignCollection, класс, содержащийся в коллекции, должен иметь внешнее поле для родительского класса.

В вашем случае PhytoterapicItem расширяет класс DomainItem, который имеет ForeignCollection объектов ContentItem. Это означает, что ContentItem должно иметь внешнее поле типа PhytoterapicItem. В противном случае, как ORMLite знать, какие из элементов ContentItem в таблице связаны с конкретным PhytoterapicItem.

Пример объектов Account и Order в документации иностранной коллекции может помочь вам с вашей схемой. Каждый Account имеет чужой набор объектов Order. Всякий раз, когда вы запрашиваете Account, выполняется отдельный запрос, чтобы найти коллекцию объектов Order, которые соответствуют конкретному Account. Это означает, что каждый Order должен иметь внешний объект Account.

Ответ 2

Мне потребовалось некоторое время, чтобы заметить/понять этот критический блок из документов (http://ormlite.com/docs/foreign-collection):

Помните, что когда у вас есть поле ForeignCollection, класс в коллекции должен (в данном примере Order) иметь внешнее поле для класса с коллекцией (в этом примере Account). Если у Учетной записи есть иностранная коллекция Заказов, тогда у Ордера должно быть поле с иностранной учетной записью. Это необходимо, чтобы ORMLite мог найти заказы, соответствующие конкретной учетной записи.

Причина, по которой я был смущен, заключается в том, что я не нашел кода примера (в документах или проектах примеров), где "содержащийся класс" ссылается на класс с коллекцией. Это описано в устной форме, но с учетом характера отношений - для некоторых описание, которое, я думаю, может быть немного сложным, когда вы видите его первые несколько раз.

Как указано выше в исходном вопросе (вот как я наконец получил идею попробовать решение, на которое я наткнулся), примерный блок ниже кажется правильным способом to-many в OrmLite.

Кроме того, есть примечание о том, как класс коллектора должен быть установлен в класс элемента коллекции.


Вот основные шаги, которые необходимо выполнить:

а. В классе, который имеет коллекцию ( DomainItem в этом случае), аннотируйте поле коллекции следующим образом:

@ForeignCollectionField(eager = true)

В. В классе, который содержится в коллекции ( ContentItem в этом случае), вы должны иметь явную ссылку на родительский класс, содержащий коллекцию:

@DatabaseField(foreign = true) protected DomainItem domainItem;

С. Перед сохранением ContentItem вы должны сохранить DomainItem в этом ContentItem, чтобы вернуть внешний ключ к DomainItem:

curContentItem.setDomainItem(curDomainItem);

contentItemDao.create(curContentItem);`

Я понял это, когда моя коллекция не извлекалась изначально. Я просмотрел таблицу для ContentItem, и DomainItem_id никогда не устанавливался там.

Пример:

public class DomainItem {

    @DatabaseField(generatedId = true)
    protected long id;

    @ForeignCollectionField(eager = false)
    protected ForeignCollection<ContentItem> contentItens;

    // ...
}


public class ContentItem {

    @DatabaseField(generatedId = true)
    protected long id;

    @DatabaseField(foreign = true)
    protected DomainItem domainItem;

    public void setDomainItem(DomainItem domainItem) {

       this.domainItem = domainItem;
    }
}