-->
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.  [ 5 posts ] 
Author Message
 Post subject: Cascade of set element type = string does not occur
PostPosted: Fri Aug 27, 2004 3:09 am 
Newbie

Joined: Wed Aug 04, 2004 4:16 pm
Posts: 12
Location: UCSC
Hi all,
I seem to have come across a point where what I see in the
hibernate source code and what I understand from Chapter 6
of the Hibernate Reference doc disagree -- so I figure that it is
my understanding that is flawed. I need some guidance telling
me what it is I am doing wrong with my mapping.

I have a set that contains strings, as shown below. This forum
is rich with examples of entity relation mappings in sets, but
I haven't found any with simple strings. My problem is that the
owning class (AttributeSet) is persisted to the database properly,
but the contained set is not persisted. Only the single SQL
statement to insert the comparatorClassNamve value is issued.
I used the eclipse debug mode to follow the execution path and
discovered that this set is expected to be cascaded after the
parent class is persisted. I then get to the following code from
net.sf.hibernate.engine.Cascades:

Code:
   /**
    * Cascade an action to the child or children
    */
   private static void cascade(
      SessionImplementor session,
      Object child,
      Type type,
      CascadingAction action,
      CascadeStyle style,
      int cascadeTo,
      Object anything
   ) throws HibernateException {
      
      if (child!=null) {
         if ( type.isAssociationType() ) {
            if ( ( (AssociationType) type ).getForeignKeyDirection().cascadeNow(cascadeTo) ) {
               if ( type.isEntityType() || type.isObjectType() ) {
                  /*if ( style.doCascade(session, child) )*/ action.cascade(session, child, anything);
               }
               else if ( type.isPersistentCollectionType() ) {
                  final int cascadeVia;
                  if ( cascadeTo==CASCADE_AFTER_INSERT_BEFORE_DELETE) {
                     cascadeVia = CASCADE_AFTER_INSERT_BEFORE_DELETE_VIA_COLLECTION;
                  }
                  else {
                     cascadeVia = cascadeTo;
                  }
                  PersistentCollectionType pctype = (PersistentCollectionType) type;
                  CollectionPersister persister = session.getFactory().getCollectionPersister( pctype.getRole() );
                  Type elemType = persister.getElementType();
                  
                  //cascade to current collection elements
                  if ( elemType.isEntityType() || elemType.isObjectType() || elemType.isComponentType() ) {
                     cascadeCollection(action, style, pctype, elemType, child, cascadeVia, session, anything);
                  }
               }
                  
            }
         }
         else if ( type.isComponentType() ) {
            AbstractComponentType componentType = (AbstractComponentType) type;
            Object[] children = componentType.getPropertyValues(child, session);
            Type[] types = componentType.getSubtypes();
            for ( int i=0; i<types.length; i++ ) {
               CascadeStyle componentPropertyStyle = componentType.cascade(i);
               if ( componentPropertyStyle.doCascade(action) ) cascade(
                  session, children[i], types[i], action, componentPropertyStyle, cascadeTo, anything
               );
            }
         }
      }
   }


The statement of interest is:
Code:
//cascade to current collection elements
if ( elemType.isEntityType() || elemType.isObjectType() || elemType.isComponentType() ) {
        cascadeCollection(action, style, pctype, elemType, child, cascadeVia, session, anything);
}

as should probably be expected when elemType == stringType, which
eclipse assured me it was. Because the if() evaluates to false, the cascade()
call returns, and no set contents are persisted.

So -- what am I doing wrong? There is an example in section 6.3 of
a set containing strings:

Quote:
Some examples, first, a set of strings:

<set name="names" table="NAMES">
<key column="GROUPID"/>
<element column="NAME" type="string"/>
</set>


and while my Xdoclet-generated mapping file has a few more
attributes defined, it certainly seems like this should work.

As you may notice, in this mapping file one thing that differs
from the example is that I had set cascade=all. I also tried
this example with the default value (none). In that case, no
cascade was attempted (as expected) but the persister.hasCollections()
was "true" -- and still the set of strings did not get persisted
(no insert statement was ever generated either).

So...help? I really did read chapter 6. And all the other
chapters. Several times. So it must just be my ability to
understand what those of you who got this sort of thing
working with no problems already do understand....

Thanks so much,
-Jen



Hibernate version:
2.1.6

Mapping documents:
Code:
<?xml version="1.0"?>
                                                                               
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
                                                                               
<hibernate-mapping>
    <class
        name="edu.se.evolution.kenyon.util.AttributeSet"
        dynamic-update="false"
        dynamic-insert="false"
    >
                                                                               
        <id
            name="id"
            column="id"
            type="java.lang.Long"
        >
            <generator class="native">
            </generator>
        </id>
        <set
            name="me"
            lazy="false"
            inverse="false"
            cascade="all"
            sort="unsorted"
        >
                                                                               
              <key
                  column="attribute_set_id"
              >
              </key>
                                                                               
              <element
                  column="value"
                  type="string"
                  not-null="false"
                  unique="false"
              />
                                                                               
        </set>
         <property
            name="comparatorClassName"
            type="java.lang.String"
            update="true"
            insert="true"
            access="property"
            column="comparatorClassName"
        />
                                                                               
        <!--
            To add non XDoclet property mappings, create a file named
                hibernate-properties-AttributeSet.xml
            containing the additional properties and place it in your merge dir.        -->
                                                                               
    </class>
                                                                               
</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():
(Junit test. I used the documentation's suggested HibernateUtil
with a modified Configuration constructor using .addClass()).
Code:
    public void testPersisting() throws HibernateException
    {
        mySet = new AttributeSet();
        mySet.add("ro");
        mySet.add("jen");
        mySet.add("areya");
        printContents();
        mySet.sortWith(new lenComparator());
        printContents();
                                                                               
        Session session = HibernateUtil.currentSession();
        Transaction tx= session.beginTransaction();
        session.save(mySet);
        tx.commit();
        HibernateUtil.closeSession();
    }


Full stack trace of any exception that occurs:
No execptions occur.

Name and version of the database you are using:
MySQL 3.23.56

Debug level Hibernate log excerpt:
Nothing wrong happens, but not everything I expected to happen
did happen.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 27, 2004 3:14 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Cascade has nothing to do with sets of value types. Its quite meaningless. The strings are deleted if they are dereferenced by the entity, or the entity itself is deleted.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 27, 2004 5:06 am 
Newbie

Joined: Wed Aug 04, 2004 4:16 pm
Posts: 12
Location: UCSC
Regarding the cascade and the set of value elements...yeah, that I suspected
but wasn't clear on. Thanks. With respect to the strings being saved
to the database at all, though, I still have no luck; no insert statement is
ever being generated for the strings. I'm tracking down the problem...
and as expected it is something I did...it seems to actually be in my setter
method for the class...before hibernate calls getSetters[i].set(object, values)
(in AbstractEntityPersister, last line of setPropertyValues(), called
from doSave(), my set has contents, and afterwards it doesn't. So.
Obviously my setter is hosed, perhaps because I had an incorrect idea
on what it was for; my setter *dereferences* the strings (using .clear()),
then tries an addAll(Set arg) to set them again. Okay...that would then invoke
the dereferencing part of your comment. Hmmm. Well, I tried the clear/addAll
approach because my internal set representation is a TreeSet, but
the argument passed in the setter is a Set, and if I don't clear the
current contents I wouldn't really be "setting" the element values
to the passed values but instead would be performing the union of the two
value sets. Hmm.

Well...could you confirm that such action in the setter would break
any later persisting to the database? What solutions to the
set vs. union issue have people used that didn't involve dereferencing
the existing strings? Thanks for the confirmation on the cascade usage,
though; I hadn't really gone through the source code yet then...

-Jen


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 27, 2004 5:11 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
(1) see the FAQ, you are not allowed to do funny stuff in collection setters and getters.
(2) If you need to do funny stuff, you must use access="field"


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 27, 2004 5:13 am 
Newbie

Joined: Wed Aug 04, 2004 4:16 pm
Posts: 12
Location: UCSC
Oh, foo, I'm too sleepy to think. I changed the setter to say
"this.me = new TreeSet(hibernate_passed_set)" and it all works
fine -- I suppose because the original this.me is neither destroyed
nor explicitly dereferenced its contents...my guess is that if I
deliberately gc()'d in the setter that it would break but it's 2:15am
and the little girl gets up at 7am if we're lucky. Thanks Gavin,
your comment helped me focus my debugging...

-Jen


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 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.