-->
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.  [ 12 posts ] 
Author Message
 Post subject: Parent/Child and many-to-one in XDoclet
PostPosted: Mon Dec 15, 2003 5:20 pm 
Beginner
Beginner

Joined: Sun Oct 05, 2003 9:07 am
Posts: 47
I have read the parent/child section in the documentation and this *should* be easy, but it just ain't workin. I have a Position object and a PositionSkills object. The Position object can have 0-n skills. Therefore, I have this XDoclet code on my getter:

Code:
    /**
     * @return a list of skills associated with this position
     *
     * @hibernate.bag name="skills" table="position_skill" inverse="false"
     *   cascade="all-delete-orphan"
     * @hibernate.collection-key column="position_id"
     * @hibernate.collection-one-to-many
     *   class="us.co.adams.apptracker.persistence.PositionSkill"
     */
    public List getSkills() {
        return skills;
    }


My PositionSkill object merely has a positionId column with the following:
Code:
     * @hibernate.property column="position_id"
     */
    public Long getPositionId() {
        return positionId;
    }

If I add an addSkill() method to my Position object, to set the positionId when adding a new skill to the Position, everything works as expected.

Here's where the problem comes into play. The documentation says I should let the PositionSkill class handle it's parent. So I change inverse to "false" on the getSkills() mapping and I add a parent property + getters/setters to the PositionSkill object. Then I map it with the following:
Code:
    /**
     * Return the position that requires these skills
     *
     * @return Position - the position that holds these skills
     * @hibernate.many-to-one name="position" column="position_id" not-null="true"
     */
    public Position getPosition() {
        return position;
    }

I have to change the getPositionId's mapping to have update="false" and insert="false". I also change the Position.addSkill method to use setParent(this) instead of setParentId(this.id). Everything *looks* right, but I get a "java.lang.StackOverflowError" when i try to run a simple test to add a positionSkill to a Position.

Any ideas?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 16, 2003 5:18 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
PositionId is useless since it's handled by the position object. Remove it.

the table attribute in bag is useless since one-to-many does not need extra tables. Remove it

If you use a many-to-one on the other side, inverse="true" on the one-to-many side is recommended http://www.hibernate.org/Documentation/InsideExplanationOfInverseTrue

The position addSkill should look like
Code:
public addSkill(Skill skill) {
  _skills.add(skill);
  skill.setPosition(this);
}


Any composite-id ? If yes, implements equals and hashCode

Otherwise try the mapping contained in the doc and change it until it looks like yours, then try to use xdoclet

_________________
Emmanuel


Top
 Profile  
 
 Post subject: StackOverFlow
PostPosted: Tue Dec 16, 2003 10:23 am 
Beginner
Beginner

Joined: Sun Oct 05, 2003 9:07 am
Posts: 47
I tried your suggestions and I just get a StackOverFlow error again. Here's my generated mapping for position:

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="us.co.adams.apptracker.persistence.Position"
        table="position"
        dynamic-update="false"
        dynamic-insert="false"
    >

        <id
            name="id"
            column="id"
            type="java.lang.Long"
            unsaved-value="null"
        >
            <generator class="native">
            </generator>
        </id>

        <property
            name="closingDate"
            type="java.util.Date"
            update="true"
            insert="true"
            column="closing_date"
        />

        <property
            name="name"
            type="java.lang.String"
            update="true"
            insert="true"
            column="name"
            length="100"
        />

        <property
            name="comments"
            type="java.lang.String"
            update="true"
            insert="true"
            column="comments"
            length="2000"
        />

        <property
            name="department"
            type="java.lang.String"
            update="true"
            insert="true"
            column="department"
            length="30"
            not-null="true"
        />

        <property
            name="description"
            type="java.lang.String"
            update="true"
            insert="true"
            column="description"
            length="2000"
            not-null="true"
        />

        <property
            name="hours"
            type="java.lang.String"
            update="true"
            insert="true"
            column="hours"
            length="50"
            not-null="true"
        />

        <property
            name="jobNumber"
            type="java.lang.String"
            update="true"
            insert="true"
            column="job_number"
            length="9"
            not-null="true"
        />

        <property
            name="location"
            type="java.lang.String"
            update="true"
            insert="true"
            column="location"
            length="30"
            not-null="true"
        />

        <property
            name="requirements"
            type="java.lang.String"
            update="true"
            insert="true"
            column="requirements"
            length="2000"
            not-null="true"
        />

        <property
            name="salary"
            type="java.lang.Integer"
            update="true"
            insert="true"
            column="salary"
        />

        <property
            name="salaryType"
            type="java.lang.String"
            update="true"
            insert="true"
            column="salary_type"
            length="10"
        />

        <bag
            name="skills"
            lazy="false"
            inverse="true"
            cascade="all-delete-orphan"
        >

              <key
                  column="position_id"
              />

              <one-to-many
                  class="us.co.adams.apptracker.persistence.PositionSkill"
              />
        </bag>

    </class>

</hibernate-mapping>


And the mapping for PositionSkill:

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="us.co.adams.apptracker.persistence.PositionSkill"
        table="position_skill"
        dynamic-update="false"
        dynamic-insert="false"
    >

        <id
            name="id"
            column="id"
            type="long"
            unsaved-value="null"
        >
            <generator class="native">
            </generator>
        </id>

        <many-to-one
            name="position"
            class="us.co.adams.apptracker.persistence.Position"
            cascade="none"
            outer-join="auto"
            update="true"
            insert="true"
            column="position_id"
            not-null="true"
        />

        <property
            name="lastUsed"
            type="java.lang.String"
            update="true"
            insert="true"
            column="last_used"
            not-null="true"
        />

        <property
            name="yearsExperience"
            type="java.lang.Integer"
            update="true"
            insert="true"
            column="years_experience"
            not-null="true"
        />

        <property
            name="name"
            type="string"
            update="true"
            insert="true"
            column="name"
            not-null="true"
            unique="false"
        />

    </class>

</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 16, 2003 10:29 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
It really helps an incredible amount to show the stack trace.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 16, 2003 10:29 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Sounds good to me. Show you code, stacktrace and log as said in
http://www.hibernate.org/ForumMailinglists/HowToAskForHelp

_________________
Emmanuel


Top
 Profile  
 
 Post subject: toString() method
PostPosted: Tue Dec 16, 2003 10:52 am 
Beginner
Beginner

Joined: Sun Oct 05, 2003 9:07 am
Posts: 47
Hmmmm, you guys are clever. My stackTrace was going into an infinite loop on my toString method, so I replaced it with ToStringBuilder.reflectionToString(this) and it fixed the issue. I don't know what's wrong with my toString() method, but it usually works fine. Any ideas?

public String toString() {
//return ToStringBuilder.reflectionToString(this);
StringBuffer results = new StringBuffer();

results.append(getClass().getName() + "\n");

// get super class as String
results.append(getClassAsString(getClass().getSuperclass()));

// get this class as String
results.append(getClassAsString(getClass()));

return results.toString();
}

private StringBuffer getClassAsString(Class clazz) {
StringBuffer results = new StringBuffer();

Field[] fields = clazz.getDeclaredFields();

try {
AccessibleObject.setAccessible(fields, true);

for (int i = 0; i < fields.length; i++) {
results.append("\t" + fields[i].getName() + "=" +
fields[i].get(this) + "\n");
}
} catch (Exception e) {
// ignored!
}

return results;
}

After all this - it's good to know how to do this, but I don't think I'll use it. On my UI, I need to do CRUD on PositionSkill - and I don't feel like storing all the position values in hidden fields. I guess I could put it into session scope or something.

Thanks for you help,

Matt


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 16, 2003 10:57 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
I hope you realize that reflectionToString() is not circular-reference-safe!


Top
 Profile  
 
 Post subject: Nevermind
PostPosted: Tue Dec 16, 2003 11:00 am 
Beginner
Beginner

Joined: Sun Oct 05, 2003 9:07 am
Posts: 47
Nevermind, toString() was getting called on the class itself - please disregard.


Top
 Profile  
 
 Post subject: reflectionToString()
PostPosted: Tue Dec 16, 2003 11:09 am 
Beginner
Beginner

Joined: Sun Oct 05, 2003 9:07 am
Posts: 47
reflectionToString() seems to work a heckuva lot better than my toString method. I replaced mine with:

public String toString() {
return ToStringBuilder.reflectionToString(this,
ToStringStyle.MULTI_LINE_STYLE);
}

And now everything works as expected (and desired).

Matt


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 16, 2003 6:49 pm 
Pro
Pro

Joined: Tue Aug 26, 2003 8:07 pm
Posts: 229
Location: Brisbane, Australia
gavin wrote:
I hope you realize that reflectionToString() is not circular-reference-safe!


It wasn't in 1.0 but is in 2.0.

_________________
Cheers,
Shorn.


Top
 Profile  
 
 Post subject: Re: reflectionToString()
PostPosted: Tue Dec 16, 2003 6:56 pm 
Pro
Pro

Joined: Tue Aug 26, 2003 8:07 pm
Posts: 229
Location: Brisbane, Australia
mraible wrote:
And now everything works as expected (and desired).


No it doesn't, you just think it does :)

Seriously, I use ToStringBuilder and it works well, but what you have to watch out for is lazy collections and proxy classes.

The new version of ToStringBuilder is not only circular-reference safe, but allows customization so that you can deal with this.

Here's the code that I have on my base persistent class (it relies on knowledge of my base class and it's getID() abstract method, but you can figure it out for yourself from there):

Code:
    /**
     * Uses the commons-lang ReflectionToStringBuilder to output something
     * useful (a bit verbos though).  Does some work to avoid initializing
     * proxied/lazied hibernate objects.
     * <p>
     * There's no reason not to write your own toString() method if you want
     * to output something a bit more precise.  Watch out for Hibernate
     * proxy objects though.
     */
    public String toString() {
        ReflectionToStringBuilder builder =
            new ReflectionToStringBuilder(this) {
                public ToStringBuilder append(
                    String fieldName, Object fieldValue)
                {
                    if(
                        fieldValue != null &&
                        fieldValue instanceof PersistentEntity
                    ){
                        PersistentEntity entity = (PersistentEntity)
                            fieldValue;
                        if( !Hibernate.isInitialized(fieldValue) ){
                            return
                                super.append(
                                    "{proxy}"+fieldName+".id",
                                    entity.getId() );
                        }
                    }
                   
                    return super.append(fieldName, fieldValue);
                }
            };
        return builder.toString();
    }
   

_________________
Cheers,
Shorn.


Top
 Profile  
 
 Post subject: StackOverflow problem in toString()
PostPosted: Thu Jun 30, 2005 2:42 am 
Newbie

Joined: Fri Jun 03, 2005 4:08 am
Posts: 12
Just spent almost a day with this problem too after following the Parent/Child section of the documentation.

Maybe that section of the document can be updated to warn future newbies about the pitfall of toString() in a bi-directional association!

-Yves-


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