-->
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.  [ 22 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Populating foreign key
PostPosted: Thu Nov 18, 2004 11:48 am 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
I have an Organisation class, which contains a List of OrganisationAddress objects. I am finding that when I try to save an address by adding it to the list and saving the parent object as in the code below, unless I have the oa.setOrganisation line the address objects get saved without the foreign keys linking them to the organisation table. I understood that I should not need to explicitly set the parent object, it should get populated automatically by Hibernate.

o=new Organisation();
o.setName("Hibernate World Enterprises");
OrganisationAddress oa=new OrganisationAddress();
oa.setBuilding("51 Rose Valley");
//Do I need this folliwng line?
oa.setOrganisation(o);
o.getAddresses().add(a);
service.storeOrganisation(o);

Rather than clutter up the message with my mapping files, I thought I'd just ask what element it is that I'm likely to be missing here. What does one need to do in a simple one to many mapping like this to ensure that the children get foreign keys populated when saving the parent object?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 12:26 pm 
Newbie

Joined: Sat Nov 13, 2004 8:09 am
Posts: 14
Location: Hamburg
What is in your mapping-file?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 12:34 pm 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
The parent:

<hibernate-mapping>
<class
name="testing.om.organisation.Organisation"
table="organisation"
dynamic-update="false"
dynamic-insert="false"
>

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

<property
name="name"
type="string"
update="true"
insert="true"
access="property"
column="name"
length="80"
/>

<property
name="acronym"
type="string"
update="true"
insert="true"
access="property"
column="acronym"
length="20"
/>

<many-to-one
name="organisationType"
class="testing.om.organisation.OrganisationType"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="organisation_type_id"
/>

<property
name="URL"
type="string"
update="true"
insert="true"
access="property"
column="url"
length="100"
/>

<property
name="telephoneNo"
type="string"
update="true"
insert="true"
access="property"
column="telephone_no"
length="40"
/>

<property
name="fax"
type="string"
update="true"
insert="true"
access="property"
column="fax"
length="40"
/>

<property
name="email"
type="string"
update="true"
insert="true"
access="property"
column="email"
length="40"
/>

<bag
name="addresses"
lazy="false"
inverse="true"
cascade="all"
>

<key
column="organisation_id"
>
</key>

<one-to-many
class="testing.om.organisation.OrganisationAddress"
/>
</bag>

<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-Organisation.xml
containing the additional properties and place it in your merge dir.
-->

</class>

</hibernate-mapping>


The child:

<?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="testing.om.Address"
table="address"
dynamic-update="false"
dynamic-insert="false"
>

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

<property
name="building"
type="string"
update="true"
insert="true"
access="property"
column="building"
length="80"
/>

<property
name="county"
type="string"
update="true"
insert="true"
access="property"
column="county"
length="40"
/>

<property
name="street"
type="string"
update="true"
insert="true"
access="property"
column="street"
length="80"
/>

<property
name="postcode"
type="string"
update="true"
insert="true"
access="property"
column="postcode"
length="20"
/>

<property
name="postalTown"
type="string"
update="true"
insert="true"
access="property"
column="postal_town"
length="80"
/>

<many-to-one
name="country"
class="testing.om.Country"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="country_id"
/>

<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-Address.xml
containing the additional properties and place it in your merge dir.
-->

<joined-subclass
name="testing.om.organisation.OrganisationAddress"
table="organisation_address"
dynamic-update="false"
dynamic-insert="false"
>
<key
column="id"
/>

<many-to-one
name="organisation"
class="testing.om.organisation.Organisation"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="organisation_id"
/>

</joined-subclass>

</class>

</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 1:18 pm 
Newbie

Joined: Sat Nov 13, 2004 8:09 am
Posts: 14
Location: Hamburg
I would suggest:
Organisation:
Code:
/**
* @hibernate.class
*/
class Organisation
{
    private Long id;
    private List addresses= new ArrayList();
    /**
      * @hibernate.id generator-class="native"
      */
    public Long getId()
    {
        return id;
    }
    private void setId(Long id)
    {
        this.id = id;
    }

    /**
      * @hibernate.bag lazy="false" inverse="true" cascade="all-delete-orphan"
      * @hibernate.collection-key column="organisation"
      * @hibernate.collection-one-to-many class="package.Addresses"
      */
    List getAddresses()
    {
        return addresses;
    }
    private void setAddresses(List addresses)
    {
        this.addresses = addresses;
    }
    public void addAddress(Address address)
    {
        address.setOrganisation(this);
        addresses.add(address);
    }
}



Address:
Code:
/**
   * @hibernate.class
   */
class Address
{
    private Long id;
    private Organisation organisation;
    /**
      * @hibernate.id generator-class="native"
      */
    public Long getId()
    {
        return id;
    }
    private void setId(Long id)
    {
        this.id = id;
    }
    /**
      * @hibernate.many-to-one not-null="true" 
      */
    public Organisation getOrganisation()
    {
         return organisation;
    }
    public void setOrganisation(Organisation organisation)
    {
        this.organisation = organisation;
    }
}


Now You have to save Organisation only once. At this point, you can add Addresses without saving easily:

Code:
Session s = {init session}
Transaction tx = s.beginTransaction();
Organisation o = new  Organisation();
s.save(o);

//are saved automatically
Address a1 = new  Address();
o.addAddress(a1);

Address a2 = new  Address();
o.addAddress(a2);

tx.commit();
s.close();


If You need the Mapping file ... just ask... Think, You are using xcdoclet;)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 1:22 pm 
Newbie

Joined: Sat Nov 13, 2004 8:09 am
Posts: 14
Location: Hamburg
When you need to add more elements at a later time You can use this code:
Code:
public void addAddress(Organisation o, Address address)
{
Session s = {init session}
Transaction tx = s.beginTransaction();

//reload Organisation (make transient object persistent
o = (Organisation)s.load(Organisation.class, o.getId(), LockMode.NONE);
o.addAddress(address);

tx.commit();
s.close();
}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 1:41 pm 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
Thanks. I'm now getting the following error at the point of saving the parent object. Any ideas why?

SEVERE: Could not synchronize database state with session
net.sf.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: sailingnetworks.om.organisation.OrganisationAddress


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 1:44 pm 
Newbie

Joined: Sat Nov 13, 2004 8:09 am
Posts: 14
Location: Hamburg
Show me the creating code...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 1:51 pm 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
The test code (which fails) I posted at the start. The actual DAO code which stores an organisation is the standard Spring saveorUpdate (the DAO class subclasses HibernateDaoSupport - I don't know whether you are familiar with Spring).

public void storeOrganisation(Organisation organisation) throws DataAccessException {
getHibernateTemplate().saveOrUpdate(organisation);
}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 1:57 pm 
Newbie

Joined: Sat Nov 13, 2004 8:09 am
Posts: 14
Location: Hamburg
I am not familiar with Spring. But i see, that you get an Organisation object from outside of a session. Is Organisation allready persistent? If so, it is detached and You have to reload it with Session.get or session.load.
So: helps this before you save?
Code:
Organisation o = session.load(Organisation.class, o.getId(), LockMode.NONE);
o.addAddress(address);


or this?

Code:
session.save(o);
o.addAddress(address);


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 1:59 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Sorry, but this is incorrect. You don't have to load() or refresh() a detached object, you reattach it. The methods are saveOrUpdate(), saveOrUpdateCopy(), or lock() if the detached object hasn't been modified.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 2:07 pm 
Newbie

Joined: Sat Nov 13, 2004 8:09 am
Posts: 14
Location: Hamburg
That is true. I was primary interested in a clean persistent object;)
"object references an unsaved transient instance" tells me, the Object is not persistent.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 2:09 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
It means it is not in a persistent state. This doesn't mean it has to be loaded from the database.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 2:09 pm 
Regular
Regular

Joined: Sun Nov 07, 2004 3:39 pm
Posts: 77
I'm not sure what an "unsaved transient instance" is. I'd like to be able to address this problem but don't know where to look.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 2:13 pm 
Newbie

Joined: Sat Nov 13, 2004 8:09 am
Posts: 14
Location: Hamburg
...and I would never use saveOrUpdate for performance and "error prone" reasons.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 18, 2004 2:20 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Wrong. Please stop giving wrong advice.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 22 posts ]  Go to page 1, 2  Next

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.