-->
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.  [ 3 posts ] 
Author Message
 Post subject: SINGLE_TABLE: Discriminator Not Recognized from Parent Class
PostPosted: Fri Jul 11, 2008 10:40 am 
Newbie

Joined: Fri Jul 11, 2008 9:50 am
Posts: 2
Hibernate version: 3.2.1.ga
Hibernate Annotations version: 3.3.1.GA
Spring Framework 2.5.3
Database: MySQL 5.0.45

Hi,

I have created a simple InheritanceType.SINGLE_TABLE example to try to debug my problem, but to no avail. It seems that the @Table, @DiscriminatorColumn, and probably @Inheritance annotations are not recognized on the abstract parent class as shown in the documentation examples.

So I had to duplicate these annotations in my child classes, which may be the source of my subsequent problem - the discriminator is not used in Hibernate generated queries, so I get all subclass instances back when I query all instances of a specific subclass.

Here are the details:

Person abstract superclass:
Code:
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.MappedSuperclass;
import javax.persistence.Table;

@MappedSuperclass
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // may be ignored by subclasses
@Table(name = "PERSON") // seems to be ignored by subclasses
@DiscriminatorColumn(name = "person_type_id", discriminatorType = DiscriminatorType.INTEGER) // seems to be ignored by subclases
public abstract class Person {
   @Id
   @GeneratedValue
   @Column(name = "person_id", nullable = false, insertable = false, updatable = false)
   private Integer personId;

   @Column(name = "name")
   private String name;

   public Integer getPersonId() {
      return personId;
   }

   public void setPersonId(Integer personId) {
      this.personId = personId;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}


Parent concrete subclass:
Code:
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "PERSON") // had to duplicate this annotation in subclasses otherwise default table name = class name (i.e. Parent) was used
@DiscriminatorColumn(name = "person_type_id", discriminatorType = DiscriminatorType.INTEGER) // had to duplicate this annotation in subclasses otherwise no discriminator column was generated by Hibernate Tools SchemaExport
@DiscriminatorValue("1")
public class Parent extends Person implements Serializable {
   @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")
   private Set<Child> children = new HashSet<Child>(0);

   public Set<Child> getChildren() {
      return children;
   }

   public void setChildren(Set<Child> children) {
      this.children = children;
   }
}


Child concrete subclass:
Code:
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "PERSON") // had to duplicate this annotation in subclasses otherwise default table name = class name (i.e. Child) was used
@DiscriminatorColumn(name = "person_type_id", discriminatorType = DiscriminatorType.INTEGER) // had to duplicate this annotation in subclasses otherwise no discriminator column was generated by Hibernate Tools SchemaExport
@DiscriminatorValue("2")
public class Child extends Person implements Serializable {
   @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
   @JoinColumn(name = "parent_id")
   private Parent parent;

   public Parent getParent() {
      return parent;
   }
   public void setParent(Parent parent) {
      this.parent = parent;
   }
}


Here is the single table that is generated via Hibernate Tools SchemaExport:
Code:
    create table PERSON (
        person_type_id integer not null,
        person_id integer not null auto_increment,
        name varchar(255),
        parent_id integer,
        primary key (person_id)
    )

    alter table PERSON
        add index FK8C768F5582F67036 (parent_id),
        add constraint FK8C768F5582F67036
        foreign key (parent_id)
        references PERSON (person_id)


Now here is the ChildDAO code:
Code:
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class ChildDAO extends HibernateDaoSupport {
   public ChildDAO() {
      super(Child.class);
   }

   public List<Child> getAll() {
      return getSessionFactory().getCurrentSession().createQuery("from Child" /* works if [where person_type_id = 2] is added */).list();
   }
}


The SQL generated by ChildDAO.getAll() is:
Code:
    select
        child0_.person_id as person2_0_,
        child0_.name as name0_,
        child0_.parent_id as parent4_0_
    from
        PERSON child0_
-- where is the missing discrimator matching clause??
-- where child0_.person_type_id = 2


So if I insert 2 parents (one with 3 children, the second with none), then I will get all 5 persons back as children:

Code:
import org.junit.Test;

public class Test {
   @Test
   public void test() {
      final Parent parent1 = new Parent();
      parent1.setName("parent1");
      final Parent parent2 = new Parent();
      parent2.setName("parent2");
      final Child child1 = new Child();
      child1.setName("child1");
      child1.setParent(parent1);
      final Child child2 = new Child();
      child2.setName("child2");
      child2.setParent(parent1);
      final Child child3 = new Child();
      child3.setName("child3");
      child3.setParent(parent1);
      final Set<Child> parent1Children = new HashSet<Child>();
      parent1Children.add(child1);
      parent1Children.add(child2);
      parent1Children.add(child3);
      parent1.setChildren(parent1Children);
      parentDAO.save(parent1);
      parentDAO.save(parent2);
      final List<Child> children = childDAO.getAll();
      final List<Child> children = childDAO.getAll();
      for(Child child : children) {
         System.out.println("child (" + ", ID = " + child.getPersonId() + ", name = " + child.getName() + ")");
      }
   }
}


This inserts the following rows into the PERSON table:
Code:
person_type_id    person_id    name        parent_id
1                 1            parent1     <null>
2                 2            child2      1
2                 3            child1      1
2                 4            child3      1
1                 5            parent2     <null>


And the following console output from the test code above:
Code:
child (ID = 1, name = parent1)
child (ID = 2, name = child2)
child (ID = 3, name = child1)
child (ID = 4, name = child3)
child (ID = 5, name = parent2)


Where did I go wrong having to duplicate @Inheriance and @DiscriminatorColumn annotations in the subclasses, and why isn't Hibernate making use of the discriminator values correctly in select clauses (although it inserts Parent and Child entities correctly with the discriminator values)?[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 14, 2008 6:49 am 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
Hi,

As you say, you should not have to duplicate all this configuration. Have you tried replacing @MappedSuperclass with @Entity in the Person class. That should work.

--Hardy


Top
 Profile  
 
 Post subject: Thanks - Worked!
PostPosted: Mon Jul 14, 2008 1:07 pm 
Newbie

Joined: Fri Jul 11, 2008 9:50 am
Posts: 2
Thanks, Hardy! Your suggestion fixed my problem.

I had previously tried to annotate Person with both @MappedSuperclass and @Entity, but never to my recollection just @Entity. Trying this (and removing the duplicate @Inheritance, @Table, and @DiscriminatorColumn annotations from Parent and Child), everything worked as expected - including HibernateTools schema generation, and subsequent inserts and selects.

Much thanks!


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