I have this abstract class:
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
}
And these (no abstract):
@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
}
In my DatabaseHelper I trying create the tables:
//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{
...
}
The table PhytoterapicContent is created. But I got the follow error:
java.sql.SQLException: Foreign collection class br.com.project.model.ContentItem for field 'contentItens' column-name does not contain a foreign field of class br.com.project.model.PhytoterapicItem
It took me a while to notice/understand this critical block from the docs (http://ormlite.com/docs/foreign-collection):
Remember that when you have a ForeignCollection field, the class in the collection must (in this example Order) must have a foreign field for the class that has the collection (in this example Account). If Account has a foreign collection of Orders, then Order must have an Account foreign field. It is required so ORMLite can find the orders that match a particular account.
The reason I was confused is because I didn't find any example code (in docs or example projects) where the "contained class" references the class with the collection. It is described verbally, but given the nature of the relationship - for some the description I think can be a bit tricky to follow when seeing it the first few times.
As listed above in the original question (which is how I finally got the idea to try the solution I stumbled upon), the example block below seems to be the correct way to map a one-to-many collection relationship in OrmLite.
In addition, there is a note about how the collection-holder class needs to be set into the collection element class.
Here are the main steps to take care of:
A. In the class that has the collection (DomainItem in this case), annotate collection field this way:
@ForeignCollectionField(eager = true)
B. In the class that is contained in the collection (ContentItem in this case), you must have an explicit reference back to the parent class that contains the collection:
@DatabaseField(foreign = true)
protected DomainItem domainItem;
C. Before persisting ContentItem, you must save the DomainItem to that ContentItem in order to set the foreign key back to DomainItem:
curContentItem.setDomainItem(curDomainItem);
contentItemDao.create(curContentItem);`
I figured this out when my collection wasn't being retrieved initially. I looked at the table for ContentItem, and the DomainItem_id was never set there.
EXAMPLE:
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;
}
}