-->
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.  [ 2 posts ] 
Author Message
 Post subject: Help, can't setup appropiate mapping type
PostPosted: Mon Jun 13, 2005 10:17 pm 
Regular
Regular

Joined: Sun May 08, 2005 2:48 am
Posts: 118
Location: United Kingdom
I have two objects Container and Thingy. Container has fields for a specific number of Thingys. Each fields has its own getter/setter methods. The container own's every thingy under it outright (there is no sharing with other instances of Containers nor any sharing between fields within one Container).

I wish to be able to create transient Container and Thingys and mess around with them as much as I'd like, assiging null Thingy's if I want to, then make one call to on the Container object and have it cascade save everything.

Code:
Container container = new Container();
// I would populate container here.
container.setThingyOne(new Thingy(1, "string"));
container.setThingyTwo(null);
// Now save everything
session.save(container);



Then later, I want to be able to load Container objects and edit/assign null Thingy's and then commit the changes.

I want hibernate to work out which old-thingy's need to be deleted in SQL and cascade delete those objects (all-delete-orphan?) and create new Thingy rows or even re-use Thingy row's (i dont care if they are re-used) if assiend new instances of Thingys.

I'm sure this is a simple relational pattern but for the life of me I can't see it.

I have one row in one table (mytable_container) referencing multiple unique rows in another (mytable_thingy) by their primary key.

At the moment I get an error when I try to persist (going from transient state) :

org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.company.Thingy#0]

I read that to mean the "identifier" is zero "#0" but that is correct for a transient object with an integral primary key (generate=native) as I want hibernate to work out its not yet persisted and persist it for me, assign its id from that op then finally persist the Container object.

Hibernate 3.0.2


Code:
Forgive me this is illustrative code, not compilable:

public class Container {
  private long id;   // Unique primary key for Container
  private Thingy thingyOne;
  private Thingy thingyTwo;
  private Thingy thingyThree;

  // There are standard getters and setters for each of those fields... here is just one
  public void setThingyOne(Thingy thingyOne) {
    this.thingyOne = thingyOne;
  }
  public Thingy getThingyOne() {
    return thingyOne;
  }
}

public class Thingy {
  private long id;   // Unique primary key for Container
  private int someValue;
  private String someString;

  // There are standard getters and setters for each of those fields...
}

The MySQL:

CREATE TABLE mytable_container (
  mytable_container_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  thingy_one INT UNSIGNED NULL,  # join with mytable_thingy_id
  thingy_two INT UNSIGNED NULL,  # join with mytable_thingy_id
  thingy_three INT UNSIGNED NULL,  # join with mytable_thingy_id
  PRIMARY KEY(mytable_container_id)
);

CREATE TABLE mytable_thingy (
  mytable_thingy_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  value_integer INT UNSIGNED NULL,
  value_string VARCHAR(255) NULL,
  PRIMARY KEY(mytable_thingy_id)
);


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 14, 2005 1:56 am 
Regular
Regular

Joined: Sun May 08, 2005 2:48 am
Posts: 118
Location: United Kingdom
I enclose the best mapping I think I've managed to put together. My problem at the moment is saving my transient objects with a single save() call and letting cascade=all do the work.

I am struggling to understand first what to call the relationship, so I can then apply the appropiate section of the hibernate manual at it.

I think the relationship is actually "one-to-many" as in one row in mytable_container references many rows in mytable_thingy (but under different joining columns from mytable_container).

However such a hibernate config mapping (according to XML DTD assitance in Eclipse does not even let me specify the column="" attribute, which can't be right at all, as the joinging column name in mytable_container is an important thing to need to specify).


To describe how the load would work:

Hibernate can either do a SELECT on the mytable_container and 1 or 3 selects on mytable_thingy during the load or it can load with a single join (as long as it re-opens the mytable_thingy under an alias for each thingyOne, thingyTwo, thingyThree).

SELECT
c.mytable_container_id,
t1.value_integer,
t1.value_string,
t2.value_integer,
t2.value_string,
t3.value_integer,
t3.value_string
FROM
mytable_container AS c,
mytable_thingy AS t1,
mytable_thingy AS t2,
mytable_thingy AS t3
WHERE
c.mytable_container_id = :priKey_I_want AND
c.thingy_one = t1.mytable_thingy_id AND
c.thingy_two = t2.mytable_thingy_id AND
c.thingy_three = t3.mytable_thingy_id;


The Thingy's are fully managed inside Container object, they never exist in their own right. For every container row there is between zero and 3 thingy rows that, the container row effectively 100% owns.


In the hibernate docs there is a attribute unsaved-value="", from the documentation this is already set to a sane default. I'm happy (and my SQL database is happy) that the value of 0 never exists in either a runtime object or a persisted record.

Unless of course the runtime object is new and transient and about to be persisted. I'm expecting hibernate to work out that "This is a new instance of this object" and therefore do INSERTs. I also expect it to work out that my Container object was the result of a previous load and when I replaced a Thingy object to also do the DELETE of the now orphaned row.

Is this possible with hibernate ?


My best effort at a mapping file:

Code:
<class name="com.company.Container" table="mytable_container">
       <id name="id" type="long" column="mytable_container_id">
           <generator class="native" />
       </id>

       <many-to-one  name="thingyOne" not-null="false" unique="true" column="thingy_one" cascade="all" />
       <many-to-one  name="thingyTwo" not-null="false" unique="true" column="thingy_two" cascade="all" />
       <many-to-one  name="thingyThree" not-null="false" unique="true" column="thingy_three" cascade="all" />
</class>

<class name="com.company.Thingy" table="mytable_thingy">
       <id name="id" type="long" column="mytable_thingy_id">
           <generator class="native" />
       </id>

       <property     name="someValue"         type="int"    column="value_integer" />
       <property     name="someString"         type="string" column="value_string" />
</class>


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