-->
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.  [ 4 posts ] 
Author Message
 Post subject: Discriminator mapping problem
PostPosted: Mon May 10, 2004 1:23 am 
Newbie

Joined: Fri May 07, 2004 2:18 am
Posts: 19
Hello I cannot figure this out.

I have 2 base classes each with 2 subclasses like this

Parent

Parent1 extends Parent

Parent2 extends Parent

and

Child

Child1 extends Child

Child2 extends Child

Child1 has a many to one relationship with Parent1
Child2 has a many to one relationship with Parent2

After reading through the docs I tried to make it work using discriminator

Here is the code

package org.marcus;

import java.io.Serializable;
import java.util.Date;
import java.util.Set;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
* @author Marcus
* @hibernate.class table="child"
* discriminator-value="M"
* @hibernate.discriminator column="type" type="character"
* Represents a contact.
*/
public class Child {
long child_id = -1;

/** Creates a new instance of Child */
public Child() {
}

/**
* @hibernate.id unsaved-value="-1" generator-class="native"
*/
public long getChild_id() {
return child_id;
}

/**
* Setter for property child_id.
* @param child_id New value of property child_id.
*/
public void setChild_id(long child_id) {
this.child_id = child_id;
}


public String toString() {
return new ToStringBuilder(this)
.append("id", getChild_id())
.toString();
}

public boolean equals(Object other) {
if ( (this == other ) ) return true;
if ( !(this.getClass().isInstance(other))) return false;
Child castOther = (Child) other;
if(this.child_id == castOther.child_id)return true;
return false;
}

public int hashCode() {
return (int)child_id;
}
}

package org.marcus;

/**
*
* @author marcus
*@hibernate.subclass table="child" discriminator-value="P"
*/
public class Child1 extends Child{
Parent1 parent;
/** Creates a new instance of Child1 */
public Child1() {
}

/**
* @hibernate.many-to-one name="parent" column="parent_id" class="org.marcus.Parent1" not-null="true"
*
*/
public Parent1 getParent() {
return parent;
}

/**
* Setter for property parent.
* @param parent New value of property parent.
*/
public void setParent(Parent1 parent) {
this.parent = parent;
}
}

package org.marcus;

/**
*
* @author marcus
*@hibernate.subclass table="child" discriminator-value="Z"
*/
public class Child2 extends Child{
Parent2 parent;
/** Creates a new instance of Child2 */
public Child2() {
}
/**
* @hibernate.many-to-one name="parent" column="parent_id" class="org.marcus.Parent2" not-null="true"
*
*/
public Parent2 getParent() {
return parent;
}

/**
* Setter for property parent.
* @param parent New value of property parent.
*/
public void setParent(Parent2 parent) {
this.parent = parent;
}
}

Here are the parents

package org.marcus;
import java.io.Serializable;
import java.util.Date;
import java.util.*;
import org.apache.commons.lang.builder.ToStringBuilder;


public class Parent {
private long parent_id = -1;

private String name;
/** Creates a new instance of Parent */
public Parent() {
}

/**
* @hibernate.id unsaved-value="-1" generator-class="native"
*/
public long getParent_id() {
return parent_id;
}

/**
* Setter for property parent_id.
* @param parent_id New value of property parent_id.
*/
public void setParent_id(long parent_id) {
this.parent_id = parent_id;
}



/**
* @hibernate.property
*/
public java.lang.String getName() {
return name;
}

/**
* Setter for property name.
* @param name New value of property name.
*/
public void setName(java.lang.String name) {
this.name = name;
}



public String toString() {
return new ToStringBuilder(this)
.append("id", getParent_id())
.toString();
}

public boolean equals(Object other) {
if ( (this == other ) ) return true;
if ( !(this.getClass().isInstance(other))) return false;
Parent castOther = (Parent) other;
if(this.parent_id == castOther.parent_id)return true;
return false;
}

public int hashCode() {
return (int)parent_id;
}

}
package org.marcus;
import java.io.Serializable;
import java.util.Date;
import java.util.*;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
* @author Marcus
* @hibernate.class table="parent1"
* Represents a contact.
*/
public class Parent1 extends Parent{
private Set children = new HashSet();
/** Creates a new instance of Parent1 */
public Parent1() {
}

public void addChild(Child1 c) {
c.setParent(this);
getChildren().add(c);
}

/**
* @hibernate.set name="children" inverse="true" cascade="all-delete-orphan"
*
* @hibernate.collection-key column="parent_id"
* @hibernate.collection-one-to-many class="org.marcus.Child1"
* @return
*/
public java.util.Set getChildren() {
return children;
}

/**
* Setter for property children.
* @param children New value of property children.
*/
public void setChildren(java.util.Set children) {
this.children = children;
}
}

package org.marcus;
import java.io.Serializable;
import java.util.Date;
import java.util.*;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
* @author Marcus
* @hibernate.class table="parent2"
* Represents a contact.
*/
public class Parent2 extends Parent{
private Set children = new HashSet();
/** Creates a new instance of Parent2 */
public Parent2() {
}

public void addChild(Child2 c) {
c.setParent(this);
getChildren().add(c);
}

/**
* @hibernate.set name="children" inverse="true" cascade="all-delete-orphan"
*
* @hibernate.collection-key column="parent_id"
* @hibernate.collection-one-to-many class="org.marcus.Child2"
* @return
*/
public java.util.Set getChildren() {
return children;
}

/**
* Setter for property children.
* @param children New value of property children.
*/
public void setChildren(java.util.Set children) {
this.children = children;
}
}

Here are the generated mappings from XDoclet

<?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="org.marcus.Child"
table="child"
dynamic-update="false"
dynamic-insert="false"
discriminator-value="M"
>

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

<discriminator
column="type"
type="character"
/>

<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-Child.xml
containing the additional properties and place it in your merge dir.
-->
<subclass
name="org.marcus.Child1"
dynamic-update="false"
dynamic-insert="false"
discriminator-value="P"
>

<many-to-one
name="parent"
class="org.marcus.Parent1"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="parent_id"
not-null="true"
/>

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

</subclass>
<subclass
name="org.marcus.Child2"
dynamic-update="false"
dynamic-insert="false"
discriminator-value="Z"
>

<many-to-one
name="parent"
class="org.marcus.Parent2"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="parent_id"
not-null="true"
/>

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

</subclass>

</class>

</hibernate-mapping>

<?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="org.marcus.Parent1"
table="parent1"
dynamic-update="false"
dynamic-insert="false"
>

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

<set
name="children"
lazy="false"
inverse="true"
cascade="all-delete-orphan"
sort="unsorted"
>

<key
column="parent_id"
>
</key>

<one-to-many
class="org.marcus.Child1"
/>
</set>

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

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

</class>

</hibernate-mapping>
<?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="org.marcus.Parent2"
table="parent2"
dynamic-update="false"
dynamic-insert="false"
>

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

<set
name="children"
lazy="false"
inverse="true"
cascade="all-delete-orphan"
sort="unsorted"
>

<key
column="parent_id"
>
</key>

<one-to-many
class="org.marcus.Child2"
/>
</set>

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

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

</class>

</hibernate-mapping>


If I run this snippet of code

Parent1 p = new Parent1();
Child1 c = new Child1();
p.addChild(c);
session.save(p);
session.flush();

I get this error
19:29:16,305 WARN JDBCExceptionReporter:38 - SQL Error: 0, SQLState: null
19:29:16,306 ERROR JDBCExceptionReporter:46 - Batch entry 0 insert into child (parent_id, type, child_id) values ( was aborted. Call getNextException() to see the cause.
19:29:16,309 WARN JDBCExceptionReporter:38 - SQL Error: 0, SQLState: 23503
19:29:16,309 ERROR JDBCExceptionReporter:46 - ERROR: insert or update on table "child" violates foreign key constraint "fk5a3f51c7b66b0d0b9579e27"

19:29:16,313 WARN JDBCExceptionReporter:38 - SQL Error: 0, SQLState: null
19:29:16,314 ERROR JDBCExceptionReporter:46 - Batch entry 0 insert into child (parent_id, type, child_id) values ( was aborted. Call getNextException() to see the cause.
19:29:16,314 WARN JDBCExceptionReporter:38 - SQL Error: 0, SQLState: 23503
19:29:16,315 ERROR JDBCExceptionReporter:46 - ERROR: insert or update on table "child" violates foreign key constraint "fk5a3f51c7b66b0d0b9579e27"

19:29:16,317 ERROR JDBCExceptionReporter:38 - Could not execute JDBC batch update
Batch entry 0 insert into child (parent_id, type, child_id) values ( was aborted. Call getNextException() to see the cause.
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:107)
at com.mchange.v2.sql.filter.FilterPreparedStatement.executeBatch(FilterPreparedStatement.java:260)
at net.sf.hibernate.impl.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:54)
at net.sf.hibernate.impl.BatcherImpl.executeBatch(BatcherImpl.java:122)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2410)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2360)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2229)
at Jubilee.Jubilee.main(Jubilee.java:76)
19:29:16,319 ERROR SessionImpl:2368 - Could not synchronize database state with session
net.sf.hibernate.JDBCException: Could not execute JDBC batch update
at net.sf.hibernate.impl.BatcherImpl.executeBatch(BatcherImpl.java:129)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2410)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2360)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2229)
at Jubilee.Jubilee.main(Jubilee.java:76)

ad infinitum.
Obviously hibernate is not providing a value to link the child1 object with its parent1 object

If I remove the Child2 Parent2 references completely it works fine.

If I run this snippet with Parent1 Child1 out of the picture
Parent2 p = new Parent2();
Child2 c = new Child2();
p.addChild(c);
session.save(p);
session.flush();

It also runs fine
Perhaps my concept of discriminator is wrong. What I really want to achieve is the following
Child Object can have a many to one relationship with either an instance of Parent 1 or Parent2 or ParentX but cant exist without either a Parent1 or a Parent2 or ParentX

Looking at the generated sql. I can see the reason its failing. For some reason its using foreign keys which can never be satisfied. What is the point of having a discriminator value if its also going to use foreign keys

alter table child drop constraint FK5A3F51C7B66B0D0;
alter table child drop constraint FK5A3F51C7B66B0D0B9579E27;
drop table child;
drop table parent1;
drop table parent2;
drop sequence hibernate_sequence;
create table child (
child_id INT8 not null,
type CHAR(1) not null,
parent_id INT8 not null,
primary key (child_id)
);
create table parent1 (
parent_id INT8 not null,
name VARCHAR(255),
primary key (parent_id)
);
create table parent2 (
parent_id INT8 not null,
name VARCHAR(255),
primary key (parent_id)
);
alter table child add constraint FK5A3F51C7B66B0D0 foreign key (parent_id) references parent1;
alter table child add constraint FK5A3F51C7B66B0D0B9579E27 foreign key (parent_id) references parent2;
create sequence hibernate_sequence;


Any help would be appreciated

Marcus


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 10, 2004 12:25 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Please simplify your code before posting, it is too much pain to help wo that simplification work.

_________________
Emmanuel


Top
 Profile  
 
 Post subject: discriminator
PostPosted: Mon May 10, 2004 8:26 pm 
Newbie

Joined: Fri May 07, 2004 2:18 am
Posts: 19
Sorry for posting so much data but it helps to be specific.
What it comes down to is my understanding of how using discriminator works. My initial impression was that it provided a way to have a many to one relationship where the child was linked to the parent but the parent could be different objects in different tables. Based on the sql code that was generated this asumption was wrong. The sql creates foreign key constraints that could never satisfy the basic concept. You cant have foreign keys that are null.
What I had hoped discriminator would do is some automagical management of these objects I wanted to create without my having to go and specifically write code myself to manage this.
At this point I still dont understand the point of discriminator and subclasses. The documentation provides brief snippets but they are ambiguous.

Marcus


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 17, 2004 2:46 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Can't understand your point.
discriminator is used to know to which (sub-)class a row has to be filled into. No link to many-to-one.

_________________
Emmanuel


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