Collections in ORMLite

Bandzio picture Bandzio · Apr 2, 2011 · Viewed 23k times · Source

Hello I want persist some collections data with ORMlite in my android app. For example :

class Person {
  @DatabaseField(generatedId=true)
  private int id;

  @DatabaseField
  private String name;

  @DatabaseField
  private String surname;

  @ForeignCollectionField
  private Collections<Phone> phones;
}

class Phone {
  @DatabaseField(generatedId=true)
  private int id;

  @DatabaseField
  private String number;

  @DatabaseField
  private String type; 
}

How i should do it to persist this collection.

EDIT

I use ForeignCollectionField as you told me. But now i have another question - is possible construction like that (I changed class a little)

@DatabaseTable
public class Student {

    @DatabaseField(generatedId=true)
    private int id;

    @DatabaseField
    private String name;

    @DatabaseField
    private String surname;

    @DatabaseField
    private String semestr;

    @ForeignCollectionField
    private Collection<Adres> adres;
}

public class Adres implements Serializable {

    @DatabaseField(generatedId=true)
    private int id;

    @DatabaseField(foreign=true, columnName="student_id")
    private Student student;

    @DatabaseField
    private String miasto;

    @DatabaseField
    private String ulica;

    @DatabaseField
    private String nr;

    @ForeignCollectionField
    private Collection<Phone> phone;
}

public class Phone {

    @DatabaseField(generatedId=true)
    private int id;

    @DatabaseField
    private String number;

    @DatabaseField(foreign=true, columnName="adres_id" )
    private Adres adres;
}

I build this structure, i have it in 3 tabelas.

Student queryForStudentMarcin = simpleDao.queryForId(studentMarcin.getId());
Collection<Adres> adres = queryForStudentMarcin.getAdres();

for (Adres a : adres) {
    int id = a.getId();
    String miasto = a.getMiasto();
    String ulica = a.getUlica();
    String nr = a.getNr();
}

Then i do this and error appear:

04-03 15:55:58.392: ERROR/AndroidRuntime(6506): FATAL EXCEPTION: main
04-03 15:55:58.392: ERROR/AndroidRuntime(6506): java.lang.NullPointerException
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at com.j256.ormlite.field.FieldType.buildForeignCollection(FieldType.java:579)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at com.j256.ormlite.stmt.mapped.BaseMappedQuery.mapRow(BaseMappedQuery.java:58)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at com.j256.ormlite.stmt.SelectIterator.nextThrow(SelectIterator.java:107)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at com.j256.ormlite.stmt.SelectIterator.next(SelectIterator.java:120)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at com.example.orm.MainActivity.dodajDoBazyCollection(MainActivity.java:140)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at com.example.orm.MainActivity$2.onClick(MainActivity.java:66)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at android.view.View.performClick(View.java:2408)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at android.view.View$PerformClick.run(View.java:8816)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at android.os.Handler.handleCallback(Handler.java:587)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at android.os.Handler.dispatchMessage(Handler.java:92)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at android.os.Looper.loop(Looper.java:123)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at android.app.ActivityThread.main(ActivityThread.java:4627)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at java.lang.reflect.Method.invokeNative(Native Method)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at java.lang.reflect.Method.invoke(Method.java:521)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
04-03 15:55:58.392: ERROR/AndroidRuntime(6506):     at dalvik.system.NativeStart.main(Native Method)

Any suggestions ?

Edit2

Problem was read data from db. This procedure work ok, it's now nice, but i just use it to understand ORMlite. Thx very much Gray for help.

protected void czytajZBazy() throws SQLException {

    Dao<Student, Integer> simpleDao = getHelper().getSimpleDao();
    Dao<Adres, Integer> adresDao = getHelper().getAdresDao();
    Dao<Phone, Integer> phoneDao = getHelper().getPhoneDao();

    /**
     * wyswietl adresy dla studenta Marcin
     */
    QueryBuilder<Student, Integer> qbStudent = simpleDao.queryBuilder();;
    Where<Student, Integer> where = qbStudent.where();
    where.eq("name", "Marcin");
    PreparedQuery<Student> prepare = qbStudent.prepare();
    CloseableIterator<Student> iterator = simpleDao.iterator(prepare);
    while(iterator.hasNext()){
        Log.v("inside ", "loop");
        Student next = iterator.next();
        Log.v("sudent", ""+next.getId()+" "+next.getName()+" "+next.getSurname());

        QueryBuilder<Adres, Integer> adresQB = adresDao.queryBuilder();
        Where<Adres, Integer> where2 = adresQB.where();

        where2.eq("student_id", next.getId());

        PreparedQuery<Adres> preparedAdres = adresQB.prepare();
        CloseableIterator<Adres> iterator2 = adresDao.iterator(preparedAdres);

        while(iterator2.hasNext()){
            Log.v("iterator po adresie", "!!");
            Adres nextAdres = iterator2.next();
            Log.v("Adres", ""+nextAdres.getId()+" "+nextAdres.getMiasto());
            //wypisz telefony 
            QueryBuilder<Phone, Integer> queryPhone = phoneDao.queryBuilder();
            Where<Phone, Integer> where3 = queryPhone.where();
            where3.eq("adres_id", nextAdres.getId());

            PreparedQuery<Phone> preparedPhone = queryPhone.prepare();
            CloseableIterator<Phone> iterator3 = phoneDao.iterator(preparedPhone);

            while(iterator3.hasNext()){
                Log.v("inside phone iterator", "");
                Phone next2 = iterator3.next();
                Log.v("phone", ""+next2.getId()+" "+next2.getNumber());
            }
            iterator3.close();
        }
        iterator2.close();
    }
    iterator.close();
}

Answer

Gray picture Gray · Apr 2, 2011

There are a number of resources and manuals that help with the usage of ORMLite under Android.

http://ormlite.com/docs/android
http://ormlite.com/docs/android-examples

To persist a collection, you must first get a Dao for the class and then create each of the objects using the Dao:

Dao<Person, Integer> personDao =
    DaoManager.createDao(androidConnectionSource, Person.class);
for (Person person : personCollection) {
    personDao.create(person);
}

Pretty much the same for your Phone class as well.


He was really asking about how to use the ForeignCollectionField feature of ORMLite. The documentation for this can be found here:

http://ormlite.com/docs/foreign-collection

There is also an example project that uses it. In the above example, you are missing a Person field inside of Phone. If the person has a collection of phone objects then each phone object needs to have a corresponding person. This is called a "foreign object" in ORMLite.

http://ormlite.com/docs/foreign-object