Hibernate versoin: 2.1.8
Others: using Spring and AndroMDA for code generation
Hi,
I guess this is a very common question: about adding and removing objects from a collection without initializing it:
my code looks like this (using Spring):
Code:
Rolodex rolodex = user.getRolodex ();
if (contact.getId()==null) getHibernateTemplate ().save (contact);
if (rolodex.getContacts()==null) rolodex.setContacts (new HashSet());
rolodex.getContacts ().add (contact);
update (rolodex);
Simply put, I have users, which have rolodexes which contain contacts wich are Person entities. those Person entities can belong to several users' rolodexes at the same time. Hence I've modeled a many-to-many relationship between rolodex and contacts
The previous code is a disaster. It generates the following:
Code:
Hibernate: select contacts0_.ROLODEXS_FK as ROLODEXS1___, contacts0_.CONTACTS_FK as CONTACTS2___ from ROLODEX_CONTACTS contacts0_ where contacts0_.ROLODEXS_FK=? order by contacts0_.CONTACTS_FK
Hibernate: select personimpl0_.ID as ID1_, personimpl0_.FIRSTNAME as FIRSTNAME42_1_, personimpl0_.LASTNAME as LASTNAME42_1_, personimpl0_.BIRTHDATE as BIRTHDATE42_1_, personimpl0_.MIDDLE_NAME as MIDDLE_N5_42_1_, personimpl0_.EMAIL as EMAIL42_1_, personimpl0_.PHONE as PHONE42_1_, personimpl0_.MOBILE as MOBILE42_1_, personimpl0_.WORK_PHONE as WORK_PHONE42_1_, personimpl0_.PERSONAL_EMAIL as PERSONA10_42_1_, personimpl0_.ICQ_NUMBER as ICQ_NUMBER42_1_, personimpl0_.MSN_ID as MSN_ID42_1_, personimpl0_.SKYPE_ID as SKYPE_ID42_1_, personimpl0_.SKYPE_NUMBER as SKYPE_N14_42_1_, personimpl0_.FAX as FAX42_1_, personimpl0__2_.TIMESTAMP as TIMESTAMP26_1_, personimpl0__2_.CORE_M_D_FK as CORE_M_D3_26_1_, userimpl1_.ID as ID0_, userimpl1_.USERNAME as USERNAME0_, userimpl1_.PASSWORD as PASSWORD0_, userimpl1_.TIMESTAMP as TIMESTAMP0_, userimpl1_.PERSON_FK as PERSON_FK0_, userimpl1_.THUMBNAIL_FK as THUMBNAI6_0_, userimpl1_.ROLODEX_FK as ROLODEX_FK0_, userimpl1_.CALENDAR_FK as CALENDAR8_0_ from PERSON personimpl0_ inner join ABSTRACT_OBJECT personimpl0__1_ on personimpl0_.ID=personimpl0__1_.ID inner join RESOURCE personimpl0__2_ on personimpl0_.ID=personimpl0__2_.ID left outer join USER userimpl1_ on personimpl0_.ID=userimpl1_.PERSON_FK where personimpl0_.ID=?
Hibernate: select userimpl0_.ID as ID0_, userimpl0_.USERNAME as USERNAME0_, userimpl0_.PASSWORD as PASSWORD0_, userimpl0_.TIMESTAMP as TIMESTAMP0_, userimpl0_.PERSON_FK as PERSON_FK0_, userimpl0_.THUMBNAIL_FK as THUMBNAI6_0_, userimpl0_.ROLODEX_FK as ROLODEX_FK0_, userimpl0_.CALENDAR_FK as CALENDAR8_0_ from USER userimpl0_ where userimpl0_.PERSON_FK=?
Hibernate: select personimpl0_.ID as ID1_, personimpl0_.FIRSTNAME as FIRSTNAME42_1_, personimpl0_.LASTNAME as LASTNAME42_1_, personimpl0_.BIRTHDATE as BIRTHDATE42_1_, personimpl0_.MIDDLE_NAME as MIDDLE_N5_42_1_, personimpl0_.EMAIL as EMAIL42_1_, personimpl0_.PHONE as PHONE42_1_, personimpl0_.MOBILE as MOBILE42_1_, personimpl0_.WORK_PHONE as WORK_PHONE42_1_, personimpl0_.PERSONAL_EMAIL as PERSONA10_42_1_, personimpl0_.ICQ_NUMBER as ICQ_NUMBER42_1_, personimpl0_.MSN_ID as MSN_ID42_1_, personimpl0_.SKYPE_ID as SKYPE_ID42_1_, personimpl0_.SKYPE_NUMBER as SKYPE_N14_42_1_, personimpl0_.FAX as FAX42_1_, personimpl0__2_.TIMESTAMP as TIMESTAMP26_1_, personimpl0__2_.CORE_M_D_FK as CORE_M_D3_26_1_, userimpl1_.ID as ID0_, userimpl1_.USERNAME as USERNAME0_, userimpl1_.PASSWORD as PASSWORD0_, userimpl1_.TIMESTAMP as TIMESTAMP0_, userimpl1_.PERSON_FK as PERSON_FK0_, userimpl1_.THUMBNAIL_FK as THUMBNAI6_0_, userimpl1_.ROLODEX_FK as ROLODEX_FK0_, userimpl1_.CALENDAR_FK as CALENDAR8_0_ from PERSON personimpl0_ inner join ABSTRACT_OBJECT personimpl0__1_ on personimpl0_.ID=personimpl0__1_.ID inner join RESOURCE personimpl0__2_ on personimpl0_.ID=personimpl0__2_.ID left outer join USER userimpl1_ on personimpl0_.ID=userimpl1_.PERSON_FK where personimpl0_.ID=?
Hibernate: select userimpl0_.ID as ID0_, userimpl0_.USERNAME as USERNAME0_, userimpl0_.PASSWORD as PASSWORD0_, userimpl0_.TIMESTAMP as TIMESTAMP0_, userimpl0_.PERSON_FK as PERSON_FK0_, userimpl0_.THUMBNAIL_FK as THUMBNAI6_0_, userimpl0_.ROLODEX_FK as ROLODEX_FK0_, userimpl0_.CALENDAR_FK as CALENDAR8_0_ from USER userimpl0_ where userimpl0_.PERSON_FK=?
Hibernate: select personimpl0_.ID as ID1_, personimpl0_.FIRSTNAME as FIRSTNAME42_1_, personimpl0_.LASTNAME as LASTNAME42_1_, personimpl0_.BIRTHDATE as BIRTHDATE42_1_, personimpl0_.MIDDLE_NAME as MIDDLE_N5_42_1_, personimpl0_.EMAIL as EMAIL42_1_, personimpl0_.PHONE as PHONE42_1_, personimpl0_.MOBILE as MOBILE42_1_, personimpl0_.WORK_PHONE as WORK_PHONE42_1_, personimpl0_.PERSONAL_EMAIL as PERSONA10_42_1_, personimpl0_.ICQ_NUMBER as ICQ_NUMBER42_1_, personimpl0_.MSN_ID as MSN_ID42_1_, personimpl0_.SKYPE_ID as SKYPE_ID42_1_, personimpl0_.SKYPE_NUMBER as SKYPE_N14_42_1_, personimpl0_.FAX as FAX42_1_, personimpl0__2_.TIMESTAMP as TIMESTAMP26_1_, personimpl0__2_.CORE_M_D_FK as CORE_M_D3_26_1_, userimpl1_.ID as ID0_, userimpl1_.USERNAME as USERNAME0_, userimpl1_.PASSWORD as PASSWORD0_, userimpl1_.TIMESTAMP as TIMESTAMP0_, userimpl1_.PERSON_FK as PERSON_FK0_, userimpl1_.THUMBNAIL_FK as THUMBNAI6_0_, userimpl1_.ROLODEX_FK as ROLODEX_FK0_, userimpl1_.CALENDAR_FK as CALENDAR8_0_ from PERSON personimpl0_ inner join ABSTRACT_OBJECT personimpl0__1_ on personimpl0_.ID=personimpl0__1_.ID inner join RESOURCE personimpl0__2_ on personimpl0_.ID=personimpl0__2_.ID left outer join USER userimpl1_ on personimpl0_.ID=userimpl1_.PERSON_FK where personimpl0_.ID=?
..... (and on and on and on and on)...
I've read the faq entry about this, but it is a bit unclear to me:
Quote:
Unfortunately the collections API defines method return values that may only be computed by hitting the database. There are three exceptions to this: Hibernate can add to a <bag>, <idbag> or <list> declared with inverse="true" without initializing the collection; the return value must always be true.
Now, actually I am a bit limited by what AndroMDA can offer, but I can maybe talk about this issue to the developers.
However, could somebody tell me if the following:
Code:
<set name="contacts" table="ROLODEX_CONTACTS" order-by="CONTACTS_FK" outer-join="auto" lazy="true" inverse="false">
<key foreign-key="ROLODEX_CONTACTS_FKC">
<column name="ROLODEXS_FK"/>
</key>
<many-to-many class="fractals.psychos.core.ontology.entity.PersonImpl" column="CONTACTS_FK" foreign-key="ROLODEX_CONTACTS_FKC"/>
</set>
could be generated using bag, idbag or list without changing the semantics. I do not understand what "the return value must always be true" actually means in this context.
Quote:
If you want to avoid extra database traffic (ie. in performance critical code), refactor your model to use only many-to-one associations. This is almost always possible. Then use queries in place of collection access.
OK: in my case (rolodex/contacts) it is really impossible to model the relationship as many-to-one (or is it?). Anyway I don't think a query could help me in the case of
adding an entity to a collection.
At this time, I'm really stuck here: the performance is
really unacceptable, and I can see no other solution than to bypass hibernate and access the database myself (which would really make me feel bad)
bernard