-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 
Author Message
 Post subject: Question on cascades
PostPosted: Thu Apr 06, 2006 7:59 pm 
Beginner
Beginner

Joined: Wed Jun 15, 2005 7:14 pm
Posts: 28
I had a question about cascades. I've seen examples where a parent is created, it is given the required information, persisted to the database, and then the children are added. The cascade will nicely save the children out.

However, what if the parent is created along with all of its children *before* it is persisted to the database the first time? That's what I'm trying to do and it keeps giving me an error:

"org.hibernate.exception.ConstraintViolationException: could not insert:"

because the foreign key on the child object is null. My mapping is as follows (children of a "Product"):

Code:
<bag name="features" cascade="all-delete-orphan">
     <key column="product_id"/>
     <one-to-many class="com.rcwilley.business.product.Feature"/>
</bag>

<bag name="specifications" cascade="all-delete-orphan">
     <key column="product_id"/>
     <one-to-many class="com.rcwilley.business.product.Specification"/>
</bag>


I probably misunderstand the process but it seems like one should be able to create and populate a parent along with give it lists of subordinate data and then Hibernate should be able to sort out the order of the persistence, namely save the parent, get its ID, and use that ID to create the children objects.

So my question is, do I really have to persist the parent object *before* adding children objects to it or is there a way to have it save everything in one call to session.save(product)?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 07, 2006 12:43 am 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Add not-null="true" to the <key> elements. This makes hibernate reverse the order of saving (parent first so that there's a key, then children).


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 07, 2006 11:56 am 
Beginner
Beginner

Joined: Wed Jun 15, 2005 7:14 pm
Posts: 28
That works great, thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 16, 2006 8:46 pm 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
However, it did not work for my mapping between Region and RegionText:

<set name="regiontextsForRegionid" inverse="true" cascade="save-update">
<key not-null="true">
<column name="REGIONID" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="test.hib.Regiontext" />
</set>


FYI PK for RegionText is (regionId, locale).

Do I need to do something more?

Thx in advance,
Chuck


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 17, 2006 7:04 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
inverse="true" means "this set does not affect the regionId column of RegionText". You need to either remove insert="true", or work the other way around: set the RegionText's region, save the RegionText object, reload the Region to get the updated set.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 17, 2006 7:50 pm 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
Thanks for the reply, but by now I am confused with how which side of the one-to-many should set inverse="true" when reading the Hibernate Reference Document 3.1 again:

1.3.6. Working bi-directional links says

The rules you have to remember are straightforward: All bi-directional associations need one side as inverse. In a one-to-many association it has to be the many-side, in many-to-many association you can pick either side, there is no difference

6.3.2. Bidirectional associations

You may define a bidirectional one-to-many association by mapping a one-to-many association to the same table column(s) as a many-to-one association and declaring the many-valued end inverse="true".

<class name="Parent">
<id name="id" column="parent_id"/>
....
<set name="children" inverse="true">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
</class>

<class name="Child">
<id name="id" column="child_id"/>
....
<many-to-one name="parent"
class="Parent"
column="parent_id"
not-null="true"/>
</class>


My question is what does 1.6.3's "many-side" and 6.3.2's "many-valued end" mean the same - the "children" side? If so, my mapping of Region has the inverse="ture" on regiontexts should be correct, shouldn't it?

Thx
Chuck


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 17, 2006 8:01 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Yep, it's all correct. Therefore you'll have to add the Regions to the RegionTexts, not the other way around. That is, you can't do this:
Code:
region.getRegionTextsForRegionId().add(regionText);
sess.save(region);
Instead you have to do this:
Code:
regionText.setRegion(region);
sess.save(regionText);
sess.refresh(region);

Alternatively, you can make the many end read-only and make the collection inverse="false": the paragraphs you've quoted assume that you want to make both ends editable. You can omit the inverse="true" if you are careful about which ends you update and when.

If you want to manage the collection from the parent/one end, you should study the SQL output to see what's happening with the different options. It's all deterministic, so once you figure out what works, you can rely on that working always.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 17, 2006 8:35 pm 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
What do I need to do to make it dump SQL out when running the hibernate app?

Thx
Chuck


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 17, 2006 9:26 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
If you use a .properties file, add the line "hibernate.show_sql=true". If you use a cfg.xml file, add the line
Code:
<property name="hibernate.show_sql">true</property>


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 12, 2006 9:12 pm 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
So after some experiment and discussion in other threads (Parent/Child) it seems Parent having a collection of Child which lifecycle are bound to Parent. and Child has a composite-id which reference to Parent, the only working solution is using <key-many-to-one> for Child mapping and have the ChildId class hold a reference to the Parent class:

Code:
   <class name="test.domain.Parent" table="PARENT">
        <id name="parentid" type="long">
            <generator class="sequence">
                <param name="sequence">seq_parentId</param>
            </generator>
        </id>
        <set name="childs" inverse="true" cascade="all-delete-orphan">
            <key column="PARENTID" not-null="true" />
            <one-to-many class="test.domain.Child" />
        </set>
    </class>

    <class name="test.domain.Child" table="CHILD">
        <composite-id name="id" class="test.domain.ChildId">
            <key-many-to-one name="parent" class="test.domain.Parent" column="parentid"/>
            <key-property name="childnumber"/>
        </composite-id>
    </class>


and then Parent and Child can be persisted in one go

Code:
           // Pres tier construct obj graph
           Parent p = new Parent();
           Child c = new Child();
           ChildId cid = new ChildId(); // needs parent and childNumber
           cid.setParent(p);
           cid.setChildnumber(101);
           c.setId(cid);
           p.getChilds().add(c);
         
           // DAO tier
           Session ssn = sessionFactory.openSession(conn);
           Transaction tx = ssn.beginTransaction();
           Serializable s;
           s = ssn.save(p);
         
           tx.commit();
           ssn.close();


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 12, 2006 10:08 pm 
Expert
Expert

Joined: Tue Apr 25, 2006 12:04 pm
Posts: 260
Code:
<class name="test.domain.Child" table="CHILD">
   <composite-id name="id" class="test.domain.ChildId">
      <key-property name="parent" column="parentid"/>
      <key-property name="childnumber"/>
   </composite-id>
   <many-to-one name="parentObject" class="test.domain.Parent" insert="false" update="false" column="parentid"/>
</class>


The above mapping will also work for Child. Using the same java code will still work to persist.

Documented here http://www.hibernate.org/117.html#A34


Top
 Profile  
 
 Post subject:
PostPosted: Sat May 13, 2006 1:50 am 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
hi bkmr_77,

thanks for the reply. I've tried the mapping you suggested without success before I was shown the alternative mapping I reported above. The problem with the mapping you mentioned is that ChildId class is like this

Code:
public class ChildId {
    private long parentId;
    private long childnumber;
    ...
}


With this ChildId, my sample Java code won't even compile - ChildId class does not take Parent class as attribute and Pres tier does not konw what's the parentId (not available until the DAO process the object graph of Parent/Child). Do you know other way to get this work without using <key-many-to-one>?


Top
 Profile  
 
 Post subject:
PostPosted: Sat May 13, 2006 2:43 am 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
Here is the stacktrace of the exception I've got using the mapping you suggested:

Code:
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).Hibernate: select SCOTT.seq_parentId.nextval from dual
Hibernate: /* get current state Child */ select child_.parentid, child_.childnumber from SCOTT.CHILD child_ where child_.parentid=? and child_.childnumber=?

log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" org.hibernate.exception.GenericJDBCException: could not retrieve snapshot: [Child#component[parent,childnumber]{childnumber=101, parent=2c6d8085f3f28086d0e1f2e5eef4cac004c7cfaf178c828083ca8088f0e1f2e5eef4e9e4cc8086e3e8e9ece4f3f4808fcceae1f6e1aff5f4e9ecafd3e5f4bbcc8087efe3e8e9ece4f3f180fe8081f8f080808080808080e9f3f280a6eff2e7aee8e9e2e5f2eee1f4e5aee3efecece5e3f4e9efeeaed0e5f2f3e9f3f4e5eef4d3e5f47b46ce7cc9bbab95828081cc8083f3e5f4f180fe8081f8f280b5eff2e7aee8e9e2e5f2eee1f4e5aee3efecece5e3f4e9efeeaec1e2f3f4f2e1e3f4d0e5f2f3e9f3f4e5eef4c3efecece5e3f4e9efee11b922b50d852395828083da808be9eee9f4e9e1ece9fae5e4cc8092e3efecece5e3f4e9efeed3eee1f0f3e8eff4f480a9cceff2e7afe8e9e2e5f2eee1f4e5afe5eee7e9eee5afc3efecece5e3f4e9efeed3eee1f0f3e8eff4bbcc8085eff7eee5f2f48092cceae1f6e1afece1eee7afcfe2eae5e3f4bbf8f081f3f280a4eff2e7aee8e9e2e5f2eee1f4e5aee5eee7e9eee5aec3efecece5e3f4e9efeec5eef4f2f9cc130385ad4880c5828085da8085e4e9f2f4f9da808be9eee9f4e9e1ece9fae5e4cc8089ecefe1e4e5e4cbe5f9f48096cceae1f6e1afe9efafd3e5f2e9e1ece9fae1e2ece5bbcc8084f2efece5f48092cceae1f6e1afece1eee7afd3f4f2e9eee7bbcc8088f3eee1f0f3e8eff4f180fe8089f8f08081f0f0f3f28091eae1f6e1aef5f4e9ecaec8e1f3e8cde1f085875a414396e051838082c6808aecefe1e4c6e1e3f4eff2c98089f4e8f2e5f3e8efece4f8f0bfc0808080808081f7888080808280808081f3f28085c3e8e9ece438bede48d3a2ad53828082cc8082e9e4f48089ccc3e8e9ece4c9e4bbcc8086f0e1f2e5eef4f48088ccd0e1f2e5eef4bbf8f0f3f28087c3e8e9ece4c9e49ed6185d18639f61828083ca808be3e8e9ece4eef5ede2e5f2ca8088f0e1f2e5eef4e9e4cc8086f0e1f2e5eef4f180fe8090f8f080808080808080e58080808080808080f180fe8082f180fe8082f180fe8091f8f0f3f28091eae1f6e1aef5f4e9ecaec8e1f3e8d3e5f43ac40515163837b4838080f8f0f78c80808082bfc0808080808081f180fe8091f8f3f180fe808381f3f180fe80888081f0f0f3f180fe808cbfc0808080808080f7888080808180808080f8f0f3f180fe8094f78c80808081bfc0808080808080f8}]
   at org.hibernate.exception.ErrorCodeConverter.handledNonSpecificException(ErrorCodeConverter.java:92)
   at org.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:80)
   at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
   at org.hibernate.persister.entity.BasicEntityPersister.getDatabaseSnapshot(BasicEntityPersister.java:893)
   at org.hibernate.engine.PersistenceContext.getDatabaseSnapshot(PersistenceContext.java:302)
   at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:189)
   at org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:409)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:82)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:468)
   at org.hibernate.engine.Cascades$5.cascade(Cascades.java:154)
   at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:771)
   at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
   at org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:895)
   at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:792)
   at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
   at org.hibernate.engine.Cascades.cascade(Cascades.java:847)
   at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:363)
   at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)
   at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:160)
   at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:108)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:184)
   at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:173)
   at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
   at org.hibernate.impl.SessionImpl.save(SessionImpl.java:481)
   at org.hibernate.impl.SessionImpl.save(SessionImpl.java:476)
   at ParentChild.main(ParentChild.java:31)
Caused by: java.sql.SQLException: ORA-00932: inconsistent datatypes

   at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
   at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
   at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
   at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:743)
   at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:216)
   at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:799)
   at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1039)
   at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:839)
   at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1132)
   at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3285)
   at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3329)
   at org.hibernate.persister.entity.BasicEntityPersister.getDatabaseSnapshot(BasicEntityPersister.java:868)
   ... 25 more


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.