Android OrmLite Foreign Key / Foreign Collection

4.3k Views Asked by At

On my recent project on Android Im using OrmLite to model one-to-many relations as well as simple one-to-one relations. Ive noticed that with one-to-many relations, the child holds the foreign key reference to the parent in the database. Still when loading the parent object OrmLite knows what to do and loads the collection of child elements which is, of course, the desired behavior.

However, with simple one-to-one relationships, the parent object seems to be required holding the foreign key column in order to achieve the same behavior.

So the actual question: Is it possible to have OrmLite loading the child objects in one-to-one relations when the foreign key is only set in the child, as it is the standard behavior with one-to-many relations?

Here is some example code:

@DatabaseTable
public class Parent
{  

@DatabaseField(foreign = true)
private Child1 child1;

@ForeignCollectionField
private Collection<Child2> children2;

}

So in child 1 and 2 I need to have the reference to the Parent like this:

 public class Child1 / Child2
{       

    @DatabaseField(foreign = true)
    private Parent parent;
}

So when saving a child2 I simply set

child2.setParent(parent);
child2Dao.create(child2)

But in order to arrive at the same behavior when querying the parent including the child1 and child2 I would have to save the relationship the other way around:

parent.setChild1(child1)
parentDao.create(parent)

This is very inconvenient as I want either child1/child2 both holding the foreign key of the parent or the other way around. But a mixture seems somewhat ugly!

Any ideas how to achieve that?

Ive searched for answers to that question here but couldnt find one. In case it is a duplicate, Im sorry!

Thank you very much!

Edit:

To be more precisely: Is it possible to set the Foreign Key in my child1 table and still be able to obtain child1 when querying for the Parent. ORMLite does it automagically for the foreign collection of child2. I want the same behavior for child1. But when I set

child1.setParent(parent);
child1Dao.create(child1);

and then make a query

Parent parent = parentDao.queryForId(1)

only child2 is obtained since the Parent Table does not have a reference (foreign key) to the child1. Only child1 has a reference to the parent.

So: I want either have OrmLite automatically update the parent foreign key column or tell Ormlite to still obtain child1 even though no foreign key is set in the parent (as this is exactly the case with the collection of child2). Is this somehow possible? Or not?

I hope this is not too confusing :) Im totally aware that it would be simpler to just set the foreign key in the parent. But I really dislike that approach as I will end up with some children having a foreign key of the parent and some that do not.

Thank you very much

2

There are 2 best solutions below

2
Luiz Fernando Salvaterra On

ORMLite supports the concept of "foreign" objects where one or more of the fields correspond to an object are persisted in another table in the same database. For example, if you had an Order objects in your database and each Order had a corresponding Account object, then the Order object would have foreign Account field. With foreign objects, just the id field from the Account is persisted to the Order table as the column "account_id". For example, the Order class might look something like:

@DatabaseTable(tableName = "orders")
public class Order {

    @DatabaseField(generatedId = true)
    private int id;

    @DatabaseField(canBeNull = false, foreign = true)
    private Account account;
    …
}

When the Order table was created, something like the following SQL would be generated:

CREATE TABLE `orders`
   (`id` INTEGER AUTO_INCREMENT , `account_id` INTEGER,
    PRIMARY KEY (`id`)); 

When you are creating a field with a foreign object, please note that the foreign object will not automatically be created for you. If your foreign object has a generated-id which is provided by the database then you need to create it before you create any objects that reference it. For example:

Account account = new Account("Jim Coakley");
accountDao.create(account);
// this will create the account object and set any generated ids

// now we can set the account on the order and create it
Order order = new Order("Jim Sanders", 12.34);
order.setAccount(account);
…
orderDao.create(order);

A foreign collection allows you to add a collection of orders on the account table. Whenever an Account object is returned by a query or refreshed by the DAO, a separate query is made over the order table and a collection of orders is set on the account. All of the orders in the collection have a corresponding foreign object that matches the account. For example:

public class Account {
    …
    @ForeignCollectionField(eager = false)
    ForeignCollection<Order> orders;
    …
}

In the above example, the @ForeignCollectionField annotation marks that the orders field is a collection of the orders that match the account. The field type of orders must be either ForeignCollection or Collection – no other collections are supported because they are much heavier with many methods to support.

Source: http://ormlite.com/

2
Alexandre On

According to ORMLite documentation, the DatabaseField is, by default, with canBeNull = true. So, it is not necessary to set the Parent when creating a Child1. To obtain the Childs in the Parent and vice-versa, you can set foreignAutoRefresh = true.

If you want to leave the foreign key column in only one table, maybe you can achieve that by setting maxForeignAutoRefreshLevel = 1.