-->
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.  [ 15 posts ] 
Author Message
 Post subject: OneToMany problem - foreign key NULL
PostPosted: Mon Jan 30, 2006 9:20 am 
Newbie

Joined: Mon Jan 30, 2006 7:39 am
Posts: 6
Hi, I'm using:

Hibernate 3.1rc2 with
Annotations: 3.1beta6
MySql 5.0.13-rc, HSQLDB 1.8.0

I have the following problem:

I have a hierarchy of classes, that I want to persist to the database. Everything was going just fine, I managed to get Hibernate persist them the way I wanted.
(source listing follows shortly - I'll explain the problem first)

But then I wanted to add a collection of entities using the @OneToMany (Unidirectional) association to one point (class) in the hierarchy. I used the following annotation:

Code:
   @OneToMany (cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = EventComment.class)
   @JoinColumn (name = "event_fk", referencedColumnName = "id")
   private Collection<EventComment> comments = new ArrayList<EventComment>(0);


So I tried to persist such an object (a concrete class of course - see below). Everything seemed OK...the cascading worked fine - the collection elements made it to the database...all seemed well except for the little detail, that the foreign key "event_fk" (Hibernate correctly added the column to the right table) remained NULL. Naturally, this means, that the collection IS persisted for the object, but when Hibernate tries to read it back from the database, the foreign keys are missing and so the returned collection is empty...

I also tried the recommended way - via a JoinTable, but the results were similar - the jointable was created, the collection elements were persisted correctly, but the jointable stayed empty...

here's the source listing for the classes in question (without irrelevant methods & fields of course )

Code:
@EmbeddableSuperclass (access = AccessType.FIELD)
public abstract class AbstractEvent implements Serializable {
   ...
}

@Entity (access = AccessType.FIELD)
@Table (name = "object_events")
@Inheritance (strategy = InheritanceType.JOINED)
public abstract class ObjectEvent extends AbstractEvent {
   
   /** The primary key of this object. */
   @Id (generate = GeneratorType.AUTO)
   private Long id = null;
   
   ...
}

@Entity (access = AccessType.FIELD)
@Table (name = "warning_events")
@Inheritance (strategy = InheritanceType.JOINED)
@PrimaryKeyJoinColumn (name = "id")
public abstract class WarningEvent extends ObjectEvent {
   
   /** The operator comment(s) for this event. */
   @OneToMany (cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = EventComment.class)
   @JoinColumn (name = "event_fk", referencedColumnName = "id")
   private Collection<EventComment> comments = new ArrayList<EventComment>(0);
   
   ...
}


! There are of course concrete classes that extend the abstract ones above...

Code:
@Entity (access = AccessType.FIELD)
@Table (name = "timeouts")
@PrimaryKeyJoinColumn (name = "id")
public class TimeoutEvent extends WarningEvent {
   ...
}


and here's the entity that's contained in the collection

Code:
@Entity (access = AccessType.FIELD)
@Table (name = "event_comments")
public class EventComment implements Serializable {

   /** primary key */
   @Id (generate = GeneratorType.AUTO)
   private Long id;
}



I searched the manuals, various forums, googled as hell, but I could't get it work correctly. I think I must've made a silly mistake somewhere and maybe it's plain to see, but I just can't find what's wrong...so any help is really appreciated. Thanx in advance...hope someone reads this :)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 30, 2006 10:12 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
this should work. Double check your equals/hashcode implementation

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 30, 2006 11:02 am 
Newbie

Joined: Mon Jan 30, 2006 7:39 am
Posts: 6
I also think it SHOULD work...but it doesn't...

I double and tripple-checked everything, but found nothing odd...

( I haven't checked the equals/hashcode as you say - what do I need to check about that ? )


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 30, 2006 11:05 am 
Newbie

Joined: Mon Jan 30, 2006 7:39 am
Posts: 6
when you say everything seems OK and that it should work, could you please make up a checklist of things that have to be done before this works ? just to make sure...

maybe I missed something (or screwed something up so that it doesn't work)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 30, 2006 1:14 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
In the unit test suite, check o.h.a.test.onetomany.OneToManyTest

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 31, 2006 5:35 am 
Newbie

Joined: Mon Jan 30, 2006 7:39 am
Posts: 6
mmm...I hope this won't sound stupid, but I couldn't find the package/class you're reffering to...well, I googled something out (for example this), but those all seemed like custom-made classes (tests) so I think you did mean something else...

I take it "check o.h.a.test.onetomany.OneToManyTest" means that I should try if this works ? OK I'd love to, but please tell me where to look...tnx :)[/list]


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 31, 2006 6:10 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
in the Hibernate annotation distribution,
test/org.hibernate/test/annotations/onetomany

this is also available on CVSWeb at sourceforge

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 31, 2006 7:03 am 
Regular
Regular

Joined: Tue Mar 23, 2004 2:10 am
Posts: 51
Hi,

I am facing the very similiar issue rather i say identical one. I am using Hibernate 3.1.2 And Hibernate Annotations 3.1 beta 8 with Oracle 10g. I have two tables in databse namely Department and Employee...having one to many relationship . Just to mention i am using bidirectional mapping. Now when i save a new Department model with newly ceated Employee collection inside...it is cascaded but the foriegn key is NULL.

My code is as follows
Code:
package com.inov8.iserv.common.model;

import java.util.*;

import javax.persistence.*;

import com.inov8.iserv.common.model.framework.*;
import org.apache.commons.lang.builder.*;

/**
* The DepartmentModel entity bean.
*
* @author  Shoaib Akhtar  Finalist IT Group
* @version $Revision: 1.16 $, $Date: 2006/01/20 13:10:17 $
*
*
*
*/
@Entity
@org.hibernate.annotations.Entity(dynamicInsert = true, dynamicUpdate = true)
        @javax.persistence.SequenceGenerator(name = "DEPARTMENT_seq",
        sequenceName = "DEPARTMENT_seq")
        @Table(name = "DEPARTMENT")
public class DepartmentModel extends BasePersistableModel
{


    private Collection<EmployeeModel> departmentIdEmployeeModelList = new
            ArrayList<EmployeeModel>();

    private Long departmentId;
    private String name;

    /**
     * Default constructor.
     */
    public DepartmentModel()
    {
    }

    /**
     * Value object constructor.
     */
    public DepartmentModel(DepartmentModel value)
    {
        if (value != null)
        {
            setDepartmentId(value.getDepartmentId());
        }
        if (value != null)
        {
            setName(value.getName());
        }
    }

    /**
     * Return the primary key.
     *
     * @return Long with the primary key.
     */
    @javax.persistence.Transient
            public Long getPrimaryKey()
    {
        return getDepartmentId();
    }

    /**
     * Set the primary key.
     *
     * @param primaryKey the primary key
     */
    @javax.persistence.Transient
            public void setPrimaryKey(Long primaryKey)
    {
        setDepartmentId(primaryKey);
    }

    /**
     * Returns the value of the <code>departmentId</code> property.
     *
     */
    @Column(name = "DEPARTMENT_ID", nullable = false)
    @Id @GeneratedValue(strategy = GenerationType.SEQUENCE,
                        generator = "DEPARTMENT_seq")
    public Long getDepartmentId()
    {
        return departmentId;
    }

    /**
     * Sets the value of the <code>departmentId</code> property.
     *
     * @param departmentId the value for the <code>departmentId</code> property
     */
    public void setDepartmentId(Long departmentId)
    {
        this.departmentId = departmentId;
    }

    /**
     * Returns the value of the <code>name</code> property.
     *
     */
    @Column(name = "NAME", nullable = false, length = 50)
    public String getName()
    {
        return name;
    }

    /**
     * Sets the value of the <code>name</code> property.
     *
     * @param name the value for the <code>name</code> property
     */
    public void setName(String name)
    {
        this.name = name;
    }


    /**
     * Add the related EmployeeModel to this one-to-many relation.
     *
     * @param employeeModel object to be added.
     */

    public void addDepartmentIdEmployeeModel(EmployeeModel employeeModel)
    {
        departmentIdEmployeeModelList.add(employeeModel);
    }

    /**
     * Get a list of related EmployeeModel objects of the DepartmentModel object.
     * These objects are in a bidirectional one-to-many relation by the DepartmentId member.
     *
     * @return Collection of EmployeeModel objects.
     *
     */
    @OneToMany(cascade =
               {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH},
               fetch = FetchType.LAZY,
               mappedBy = "relationDepartmentIdDepartmentModel")
    @JoinColumn(name = "DEPARTMENT_ID")
    @org.hibernate.annotations.Cascade(
            {org.hibernate.annotations.CascadeType.
            SAVE_UPDATE,
            org.hibernate.annotations.CascadeType.
            PERSIST,
            org.hibernate.annotations.CascadeType.
            MERGE,
            org.hibernate.annotations.CascadeType.
            REFRESH})
            public Collection<EmployeeModel> getDepartmentIdEmployeeModelList() throws
            Exception
    {
        return departmentIdEmployeeModelList;
    }

    /**
     * Set a list of EmployeeModel related objects to the DepartmentModel object.
     * These objects are in a bidirectional one-to-many relation by the DepartmentId member.
     *
     * @param employeeModelList the list of related objects.
     */
    public void setDepartmentIdEmployeeModelList(Collection<EmployeeModel>
            employeeModelList) throws Exception
    {
        this.departmentIdEmployeeModelList = employeeModelList;
    }


    /**
     * Helper method for Struts with displaytag
     */
    @javax.persistence.Transient
            public String getPrimaryKeyParameters()
    {
        String parameters = "";
        parameters += "&departmentId=" + getDepartmentId();
        return parameters;
    }

    /**
     * Helper method for default Sorting on Primary Keys
     */
    @javax.persistence.Transient
            public String[] getPrimaryKeysFieldName()
    {
        ArrayList<String> pkFieldNameList = new ArrayList<String>();
        pkFieldNameList.add("departmentId");
        String[] pkFieldNameArray = new String[pkFieldNameList.size()];
        return (String[]) pkFieldNameList.toArray(pkFieldNameArray);
    }

    public String toString()
    {
        return new ToStringBuilder(this).append("departmentId", departmentId)
                .append("name", name)
                .toString();

    }

    public boolean equals(Object other)
    {
        if (this == other)
        {
            return true;
        }
        if (!(other instanceof DepartmentModel))
        {
            return false;
        }
        DepartmentModel castOther = (DepartmentModel) other;
        return new EqualsBuilder().append(name, castOther.name).isEquals();

    }

    public int hashCode()
    {
        return new HashCodeBuilder(510071930, 30524218).append(name)
                .toHashCode();
    }
}




and
Code:
package com.inov8.iserv.common.model;

import java.util.*;

import javax.persistence.*;

import com.inov8.iserv.common.model.framework.*;
import org.apache.commons.lang.builder.*;

/**
* The EmployeeModel entity bean.
*
* @author  Shoaib Akhtar  Finalist IT Group
* @version $Revision: 1.16 $, $Date: 2006/01/20 13:10:17 $
*
*/
@Entity
@org.hibernate.annotations.Entity(dynamicInsert = true, dynamicUpdate = true)
        @javax.persistence.SequenceGenerator(name = "EMPLOYEE_seq",
        sequenceName = "EMPLOYEE_seq")
        @Table(name = "EMPLOYEE")
public class EmployeeModel extends BasePersistableModel
{


    private DepartmentModel departmentIdDepartmentModel;


    private Long employeeId;
    private String name;

    /**
     * Default constructor.
     */
    public EmployeeModel()
    {
    }

    /**
     * Value object constructor.
     */
    public EmployeeModel(EmployeeModel value)
    {
        if (value != null)
        {
            setEmployeeId(value.getEmployeeId());
        }
        if (value != null)
        {
            setDepartmentId(value.getDepartmentId());
        }
        if (value != null)
        {
            setName(value.getName());
        }
    }

    /**
     * Return the primary key.
     *
     * @return Long with the primary key.
     */
    @javax.persistence.Transient
            public Long getPrimaryKey()
    {
        return getEmployeeId();
    }

    /**
     * Set the primary key.
     *
     * @param primaryKey the primary key
     */
    @javax.persistence.Transient
            public void setPrimaryKey(Long primaryKey)
    {
        setEmployeeId(primaryKey);
    }

    /**
     * Returns the value of the <code>employeeId</code> property.
     *
     */
    @Column(name = "EMPLOYEE_ID", nullable = false)
    @Id @GeneratedValue(strategy = GenerationType.SEQUENCE,
                        generator = "EMPLOYEE_seq")
    public Long getEmployeeId()
    {
        return employeeId;
    }

    /**
     * Sets the value of the <code>employeeId</code> property.
     *
     * @param employeeId the value for the <code>employeeId</code> property
     */
    public void setEmployeeId(Long employeeId)
    {
        this.employeeId = employeeId;
    }

    /**
     * Returns the value of the <code>name</code> property.
     *
     */
    @Column(name = "NAME", nullable = false, length = 50)
    public String getName()
    {
        return name;
    }

    /**
     * Sets the value of the <code>name</code> property.
     *
     * @param name the value for the <code>name</code> property
     */
    public void setName(String name)
    {
        this.name = name;
    }

    /**
     * Returns the value of the <code>departmentIdDepartmentModel</code> relation property.
     *
     * @return the value of the <code>departmentIdDepartmentModel</code> relation property.
     *
     */
    @ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY)
    @JoinColumn(name = "DEPARTMENT_ID")
    public DepartmentModel getRelationDepartmentIdDepartmentModel()
    {
        return departmentIdDepartmentModel;
    }

    /**
     * Returns the value of the <code>departmentIdDepartmentModel</code> relation property.
     *
     * @return the value of the <code>departmentIdDepartmentModel</code> relation property.
     *
     */
    @javax.persistence.Transient
            public DepartmentModel getDepartmentIdDepartmentModel()
    {
        return getRelationDepartmentIdDepartmentModel();
    }

    /**
     * Sets the value of the <code>departmentIdDepartmentModel</code> relation property.
     *
     * @param departmentModel a value for <code>departmentIdDepartmentModel</code>.
     */
    @javax.persistence.Transient
            public void setRelationDepartmentIdDepartmentModel(DepartmentModel
            departmentModel)
    {
        this.departmentIdDepartmentModel = departmentModel;
    }

    /**
     * Sets the value of the <code>departmentIdDepartmentModel</code> relation property.
     *
     * @param departmentModel a value for <code>departmentIdDepartmentModel</code>.
     */
    @javax.persistence.Transient
            public void setDepartmentIdDepartmentModel(DepartmentModel
            departmentModel)
    {
        setRelationDepartmentIdDepartmentModel(new DepartmentModel(
                departmentModel));
    }


    /**
     * Returns the value of the <code>departmentId</code> property.
     *
     */
    @javax.persistence.Transient
            public Long getDepartmentId()
    {
        if (departmentIdDepartmentModel != null)
        {
            return departmentIdDepartmentModel.getDepartmentId();
        }
        else
        {
            return null;
        }
    }

    /**
     * Sets the value of the <code>departmentId</code> property.
     *
     * @param departmentId the value for the <code>departmentId</code> property
     */
    @javax.persistence.Transient
            public void setDepartmentId(Long departmentId)
    {
        if (departmentIdDepartmentModel == null)
        {
            departmentIdDepartmentModel = new DepartmentModel();
        }
        departmentIdDepartmentModel.setDepartmentId(departmentId);
    }

    /**
     * Helper method for Struts with displaytag
     */
    @javax.persistence.Transient
            public String getPrimaryKeyParameters()
    {
        String parameters = "";
        parameters += "&employeeId=" + getEmployeeId();
        return parameters;
    }

    /**
     * Helper method for default Sorting on Primary Keys
     */
    @javax.persistence.Transient
            public String[] getPrimaryKeysFieldName()
    {
        ArrayList<String> pkFieldNameList = new ArrayList<String>();
        pkFieldNameList.add("employeeId");
        String[] pkFieldNameArray = new String[pkFieldNameList.size()];
        return (String[]) pkFieldNameList.toArray(pkFieldNameArray);
    }


    public String toString()
    {
        return new ToStringBuilder(this).append("employeeId", employeeId)
                .append("name", name)
                .toString();

    }

    public boolean equals(Object other)
    {
        if (this == other)
        {
            return true;
        }
        if (!(other instanceof EmployeeModel))
        {
            return false;
        }
        EmployeeModel castOther = (EmployeeModel) other;
        return new EqualsBuilder().append(name, castOther.name).isEquals();

    }

    public int hashCode()
    {
        return new HashCodeBuilder(510071931, 30524219).append(name)
                .toHashCode();
    }
}



I have double checked my equals and hascode methods as well. The propert name in both model is unique and not null and it is not primary key as recommended by hibenate.And one thing i debugged my code with break points on all equals and hashcode methods but somehow it is never called. The code for saving is as follows
Code:
        DepartmentModel departmentModel = new DepartmentModel();
        departmentModel.setName("IT");

        EmployeeModel firstEmployeeModel = new EmployeeModel();
        firstEmployeeModel.setName("Shoaib");

EmployeeModel secondEmployeeModel = new EmployeeModel();
        secondEmployeeModel.setName("Shahzad");

departmentModel.addDepartmentIdEmployeeModel(firstEmployeeModel);
        departmentModel.addDepartmentIdEmployeeModel(secondEmployeeModel);

session.save(departmentModel );



Please help me asap.

Regards,
Shoaib Akhtar


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 31, 2006 7:31 am 
Regular
Regular

Joined: Tue Mar 23, 2004 2:10 am
Posts: 51
Hi Again,
I found another incomplete thread on quite similiar issue way back in March 2005. The link is as follows

http://forum.hibernate.org/viewtopic.php?t=940134&highlight=cascading

So we are not alone facing this issue.

Regards,
Shoaib Akhtar


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 31, 2006 7:48 pm 
Newbie

Joined: Mon Jan 30, 2006 7:39 am
Posts: 6
My collegue and I tried a simple test - one entity, that contains a collection of other entities (OneToMany Unidirectional way using JoinColumn) - worked perfectly...

In the mean time, we upgraded to Hibernate 3.1.2 and Annotations 3.1beta8...not that it mattered much...

Still - the problem I posted before remains. We began to suspect, that the problem may be the fact, that the entity containing the collection is a part of a hierarchy of other entities - i.e. inheritance is involved. (maybe it's a kind of a long shot, but that's the only difference we've found so far between a working and a non-working example)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 01, 2006 1:42 am 
Regular
Regular

Joined: Tue Mar 23, 2004 2:10 am
Posts: 51
Hi,
I also tried something similiar and made it a unidirectional relationship but still no avail. And the case i mentioned above even do not use inheritance at all. The BasePersistableModel mentioned in my code posted here before just has some methods define but you can safely omitt this. And i hope that it is a simple enough test case. As a matter of fact i am NOT USING Hibernate Entity Manager rather using plain Hibernate with Annotations. I think that both of us has similiar problem so i am not starting another thread but if anybody likes that i can always do that.

Regards,
Shoaib Akhtar


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 01, 2006 4:47 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
shaby775, your problem has probably nothing to do. Update both sides of your relationship. Th manytoone contains null.

unrealone: try to reproduce with 3 entities and post the running test case to JIRA

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 01, 2006 7:14 am 
Regular
Regular

Joined: Tue Mar 23, 2004 2:10 am
Posts: 51
Hi,
Thanks for your reply i also found that by reading the excellent and must have "Hibernate in Action". I also want to ask another thing but it seems to me that it is not appropriate to aks it on this thread. Thanks for excellent support.

Regrads,
Shoaib Akhtar


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 01, 2006 9:07 am 
Newbie

Joined: Mon Jan 30, 2006 7:39 am
Posts: 6
I thought that if it's a bug, it may take a while before someone has the time to do something about it...and since I need it to work NOW...

So I tried to switch to a bidirectional association and suddenly - it works !

Here's the altered mapping code for WarningEvent
Code:
      @OneToMany (mappedBy = "event", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
   private Collection<EventComment> comments = new ArrayList<EventComment>(0);


WarningEvent also has a method named addComment() for adding elements to the collection - but I found, that without explicitly setting the backward reference (from EventComment to WarningEvent) the foreign key field still remains null

Code:
   public void addComment(String author, String comment) {
     
      LOG.trace("addComment( author, comment )");
     
     
      if (author == null) {
         throw new IllegalArgumentException("param cannot be null");
      }
     
      if (comment == null) {
         throw new IllegalArgumentException("comment cannot be null");
      }
     
      // make a new comment
      EventComment newComment = new EventComment(author, comment);
     
      newComment.setEvent(this);
     
      synchronized (this.comments) {
         
         // add it to the list of comments
         this.comments.add(newComment);
      }
     
   }




...and for the other side of the relation (EventComment - collection element)
Code:
   @ManyToOne
   @JoinColumn (name = "event_fk")
   private WarningEvent event;

...

   public void setEvent(WarningEvent event) {
      this.event = event;
   }

}


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 01, 2006 8:08 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
unrealone wrote:
but I found, that without explicitly setting the backward reference (from EventComment to WarningEvent) the foreign key field still remains null[/b]


Right, this is expected. You're making the same mistake shaby775 did.

_________________
Emmanuel


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