0

I'm trying to save with GreenDAO an entity called hotel. Each hotel has a relation one-to-many with some agreements and each agreement has got... well, a picture is worth a thousand words.

enter image description here

Now, what I do is the following:

daoSession.runInTx(new Runnable() {
    @Override
    public void run() {

        ArrayList<Hotel> listOfHotels = getData().getAvailability();

            for(Hotel h : listOfHotels)
            {
                List<HotelAgreement> hotelAgreements = h.getAgreements();
                for(HotelAgreement ha : hotelAgreements) {
                    ha.setHotel_id(h.getHotel_id());
                    HotelAgreementDeadline hotelAgreementDeadline = ha.getDeadline();
                    List<HotelRemark> hr = hotelAgreementDeadline.getRemarks();
                    List<HotelAgreementDeadlinePolicies> hadp = hotelAgreementDeadline.getPolicies();

                    daoSession.getHotelReportDao().insertOrReplaceInTx( h.getReports() );
                    daoSession.getHotelPictureDao().insertOrReplaceInTx( h.getPictures() );

                    daoSession.getHotelRemarkDao().insertOrReplaceInTx(hr);
                    daoSession.getHotelAgreementDeadlinePoliciesDao().insertOrReplaceInTx(hadp);
                    daoSession.getHotelAgreementDeadlineDao().insertOrReplace(hotelAgreementDeadline);
                    daoSession.getHotelAgreementDao().insertOrReplace(ha);
                }

                //                daoSession.getHotelReportsDao().insertOrReplace( getData().getReports() );

            }

        daoSession.getHotelDao().insertOrReplaceInTx(listOfHotels);
    }
});

This, of course, does not work. I get a "Entity is detached from DAO context" error on the following line:

HotelAgreementDeadline hotelAgreementDeadline = ha.getDeadline();

I understand this is because I try to get the Agreements from a Hotel entity which does not come from the database, but from another source (a web service, in this case). But why does this happen with ha.getDeadline() and not with h.getAgreements()?

Now, I have the Hotel object and it does include pretty much all data: agreements, deadline, policies, remarks, pictures, report. I'd just like to tell GreenDAO: save it! And if I can't and I have to cycle through the tree - which is what I'm trying to do with the code above - how am I supposed to do it?

Here I read that I have to "store/load the object first using a Dao". Pretty awesome, but... how does it work? I read the greenDAO documentation about relations but couldn't find anything.

Thank you to everybody who's willing to help :-)

Community
  • 1
  • 1
Marco Zanetti
  • 4,051
  • 6
  • 32
  • 48
  • It's hard to say without knowing what getData().getAvailability(); does. Also, it would help to know how you generate the entities and what realtions you have. – Jofre Mateu Apr 13 '15 at 15:20
  • I get the response from the webservice and cast it: `responseAgreements = (HotelAvailabilityResponse) response;`. This is the object I call the getAvailability on, simply returning a List of Hotel objects. These came from the response of the webservices and have never seen the DB, and I'm able to store them into the database, but sub-items are not stored. If I try to retrieve them - like it breaks with the _Entity is detached from DAO context_ error. About relations, what would you like to know exactly? I can post pieces of my GreenDaoGenerator – Marco Zanetti Apr 13 '15 at 15:39
  • When the app loads I do the same with the breakfast_typologies. I call `daoSession.getHotelBreakfastDao().insertOrReplaceInTx(getData().getBreakfasts());` and what I get from `getData().getBreakfasts()` is a List of HotelBreakfast. But they don't have any relation with other tables, so get inserted in DB flawlessly. – Marco Zanetti Apr 13 '15 at 15:52
  • I think it would help if you past the code in `getData().getAvailability();` – Jofre Mateu Apr 13 '15 at 16:46

2 Answers2

0

At some point, when you get the response from the webservice, you are creating new entity objects and filling them with the info. Try inserting each new object in the DB just after that.

If you want, you can insert, for example, all n Agreement for an Hotel using insertOrReplaceInTx, but you shouldn't use any relation before all the involved objects are in the DB.

Jofre Mateu
  • 2,390
  • 15
  • 26
  • I believe this is what I'm doing already :-/ If I comment all the lines in the middle and I just do `ArrayList listOfHotels = getData().getAvailability(); daoSession.getHotelDao().insertOrReplaceInTx(listOfHotels);` it works, and I save all the hotels in the database (but just Hotels). Why doesn't it work with the other Entities? – Marco Zanetti Apr 13 '15 at 16:39
  • With lines like this `List hotelAgreements = h.getAgreements();` you are using the relation between Hotel and Agreement when neither the Hotel or their Agreement stored in the DB. – Jofre Mateu Apr 13 '15 at 16:44
  • Okay, I see the issue now: since the two entities are not in the database I can't get an Agreement out of a Hotel, even though the Hotel has got all the data inside of itself. But, since I got a full Hotel object, with all its sub-objects, how am I supposed to store it into the database? Did I get all the ORM-theory wrong? What approach should I try instead? Thank you. – Marco Zanetti Apr 13 '15 at 17:12
  • What do you get primarily from your webservice? A JSON maybe? Or do you get the whole Hotel object? – Jofre Mateu Apr 14 '15 at 07:42
  • I get a JSON. Jofre, should we maybe meet in chat at http://chat.stackoverflow.com/rooms/71661/android-discussions ? If you want to, I'm already there. – Marco Zanetti Apr 14 '15 at 09:01
0

I think that greendao team have to add the following control in the method getToOneField() like in the getToManyList()

if(property == null){
    code already generated by greendao plugin
}
return property;

so in your case in HotelAgreements class

@Keep
public DeadLine getDeadLine {
    if(deadLine == null) {
        long __key = this.deadLineId;
        if (deadLine__resolvedKey == null || !deadLine__resolvedKey.equals(__key)) {
            final DaoSession daoSession = this.daoSession;
            if (daoSession == null) {
                throw new DaoException("Entity is detached from DAO context");
            }
            DeadLineDao targetDao = daoSession.getDeadLineDao();
            DeadLine deadLineNew = targetDao.load(__key);
            synchronized (this) {
                deadLine = deadLineNew;
                deadLine__resolvedKey = __key;
            }
        }
    }
    return deadLine;
}

adding the control

if(deadLine == null) {
    ...
}

so if you receive data from rest json the object is populated and getProperty() method return property field from object not from database just like it does with Lists then you can insert or replace it

Then, when you load or load deeply object from db the property is null and greendao take it from DB

enrico.devita
  • 153
  • 1
  • 5