Reputation: 1404
I'm using OrmLite on android for a structure simmilar to the following :
The Book class has a collection of primary BookArticle and a collection of secondary BookArticle :
@DatabaseTable(tableName = "BookV1", daoClass = BookDaoImplV1.class)
public class Book implements IBook {
@DatabaseField(id = true)
private String id;
@ForeignCollectionField(eager = false)
private ForeignCollection<BookArticle> primaryArticles;
@ForeignCollectionField(eager = false)
private ForeignCollection<BookArticle> secondaryArticles;
// constructor getters setters etc...
}
Then the BookArticle is declared as follow :
@DatabaseTable(tableName = "BookArticleV1", daoClass = BookArticleDaoImplV1.class)
public class BookArticle implements IBookArticle {
@DatabaseField(id = true)
private String id;
@DatabaseField
private String title;
@DatabaseField
private String summary;
// for ORM mapping only
@DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = BOOK_FIELDNAME, index = true)
private Book book;
// constructor getters setters etc..
}
now saving the BookArticles and Book with DAO works fine however when I want to fetch my Book entity from database and access either primary or secondary articles (after a refresh() ) I have a problem because both collections hold ALL the articles (both primary and secondary) that have the book's id in their 'book' column.
Obviously I would need these primary and secondary articles to be separated when fetched from DB.
I would have expected "foreignFieldName" to be the answer to my problem.
@ForeignCollectionField(eager = false, foreignFieldName = "secondaryArticles")
private ForeignCollection<BookArticle> secondaryArticles;
but apparently it does not work that way.
Is there a way for me to differenciate between these two collections ? Maybe using a simple annotation argument such as "owningFieldName" or similar that would get persisted in DB alongside the BookArticle data?
Many thanks for your help.
Alex
Upvotes: 3
Views: 1156
Reputation: 36
if you want to add multible ForeignerCollections form the same typ to one class, you have to add 2 fields for ORM-Mapping in the BookArticle class and link this in the Book class to the ORM-Mapping fields.
e.g
Book class
@ForeignCollectionField(eager = false, foreignFieldName = "primaryBook")
private ForeignCollection<BookArticle> primaryArticles;
@ForeignCollectionField(eager = false, foreignFieldName = "secondaryBook")
private ForeignCollection<BookArticle> secondaryArticles;
BookArticle class
// for ORM mapping primary Books
@DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = BOOK_FIELDNAME, index = true)
private Book primaryBook;
// for ORM mapping secondary Books
@DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = BOOK_FIELDNAME, index = true)
private Book secondaryBook;
When you call now bookDao.queryAll() and access the secondary Articles list, you will see the articles are correctly linked.
The disadvantage is, that you have 2 columes in the BookArticle Table for foreigner keys.
Greeting, Codenix
Upvotes: 1
Reputation: 5020
From official doc Annotation Type ForeignCollectionField
Annotation that identifies a ForeignCollection field in a class that corresponds to objects in a foreign table that match the foreign-id of the current class.
Back to your code of Book
class
@ForeignCollectionField(eager = false)
private ForeignCollection<BookArticle> primaryArticles;
@ForeignCollectionField(eager = false)
private ForeignCollection<BookArticle> secondaryArticles;
When you refresh you collections, ormlite just does simple query
SELECT * FROM article WHERE book_id = 'id of book'
and after converts result into BookArticle
collection
If you still want to have one-to-one relationship between book and article. Then simplest way to implement your initial requirement is next:
Book class
@DatabaseTable(tableName = "BookV1", daoClass = BookDaoImplV1.class)
public class Book implements IBook {
@DatabaseField(id = true)
private String id;
@ForeignCollectionField(eager = false)
private ForeignCollection<BookArticle> articles;
public Collection<BookArticle> getArticles(boolean primary) throws SQLException {
articles.refreshCollection();
Collection<BookArticle> result = new ArrayList<BookArticle>();
for (BookArticle article : articles) {
if (article.isPrimary() == primary) result.add(article)
}
return result;
}
}
BookArticle class
@DatabaseTable(tableName = "BookArticleV1", daoClass = BookArticleDaoImplV1.class)
public class BookArticle implements IBookArticle {
private static final String BOOK_FIELDNAME = "book_id";
@DatabaseField(id = true)
private String id;
@DatabaseField
private String title;
@DatabaseField
private String summary;
@DatabaseField
private boolean primary;
public boolean isPrimary() {
return primary;
}
// for ORM mapping only
@DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = BOOK_FIELDNAME, index = true)
private Book book;
// constructor getters setters etc..
}
To do article primary you need:
true
;To get book's primary articles :
getArticles(true)
of needed book entity;For use case 'secondary' use same steps with false
value.
Upvotes: 0
Reputation: 121
I ran into the same problem.
Not a real solution but you can try to use only one list with a boolean for switching between primary/secondary articles like this:
@DatabaseTable(tableName = "BookV1", daoClass = BookDaoImplV1.class)
public class Book implements IBook {
@DatabaseField(id = true)
private String id;
@ForeignCollectionField(eager = false)
private ForeignCollection<BookArticle> articles;
// constructor getters setters etc...
}
And then for the BookArticle class
@DatabaseTable(tableName = "BookArticleV1", daoClass = BookArticleDaoImplV1.class)
public class BookArticle implements IBookArticle {
@DatabaseField(id = true)
private String id;
@DatabaseField
private String title;
@DatabaseField
private String summary;
@DatabaseField
private boolean isSecondary;
// for ORM mapping only
@DatabaseField(foreign = true, foreignAutoRefresh = true, columnName = BOOK_FIELDNAME, index = true)
private Book book;
// constructor getters setters etc..
}
Hoping to see a real answer
Upvotes: 3