1

I'm new to Java and Hibernate (although I've familiar with the Entity Framework so understand a lot of the concepts)

All I want to do is create a Table OrganisationNode which has the following fields: Id, Name and ParentId

ParentId is Nullable and, if present, should point at a valid OranisationNode.Id.

I'd assumed this should be fairly simple but having spent over 2 days googling and editing XML files, I'm starting to lose patience.

Let me start with the code snippets...

OrganisationNode.java

@javax.persistence.Entity
public class OrganisationNode extends EntityBase implements Serializable {
    private String name;

    @ManyToOne(targetEntity = OrganisationNode.class, optional = true)
    @JoinColumn(name="ParentId", referencedColumnName="Id") //This is one example of this attribute. I've tried many combinations
    private OrganisationNode parent;

    @OneToMany
    private Set<OrganisationNode> children = new HashSet<OrganisationNode>();

    //Getters/Setters
}

EntityBase.java

@javax.persistence.Entity
public class EntityBase implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    //Getter/Setter
}

Hibernate.config.xml

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://mysqldev:3306/SomeDb?zeroDateTimeBehavior=convertToNull</property>
    <property name="hibernate.connection.username">SomeUser</property>
    <property name="hibernate.connection.password">SomePass!</property>
    <property name="hibernate.hbm2ddl.auto">create</property>
    <property name="show_sql">true</property>
    <mapping resource="hibernate.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

Hibernate.hbm.xml

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.overshare.document.entities.OrganisationNode" table="OrganisationNodes">
        <id name="id"><generator class="native"/></id>
        <property name="name"/>
        <property name="children"/>
        <property name="parent"/>
    </class>
</hibernate-mapping>

HibernateUtil.java

public class HibernateUtil {

    private static SessionFactory sessionFactory;

    public static void configureSessionFactory() {

            Configuration configuration = new Configuration();
            configuration.configure("hibernate.cfg.xml");
            ServiceRegistryBuilder serviceRegistryBuilder = new ServiceRegistryBuilder().applySettings(configuration.getProperties());
            sessionFactory = configuration.buildSessionFactory(serviceRegistryBuilder.buildServiceRegistry());
    }

    public static SessionFactory getSessionFactory() {
        if(sessionFactory == null){configureSessionFactory();}
        return sessionFactory;
    }
}

The exception I currently get is ...

javax.servlet.ServletException: org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: OrganisationNodes, for columns: [org.hibernate.mapping.Column(Children)]

So, my first question is how can I resolve this exception? I believe I've explicitly told it what Children should be pointing at.

My next question is... Is this all really necessary? I find it hard to believe that getting a single table up and running on an ORM takes so much configuration and code. Most of what I've got here has been hacked from various examples on the web so I'm unsure of the quality. Surely 90% of this information must be available to hibernate via reflection?

Basic
  • 26,321
  • 24
  • 115
  • 201
  • Don't know if it's directly related to this error, but shouldn't the properties in the hbm file start with lowercase? Also, wouldn't `EntityBase` need to be a `@MappedSuperClass`? As a side note, I'd recommend sticking to a single way of defining the mappings, either annotations or hbm.xml. – Xavi López Feb 25 '13 at 16:10
  • @XaviLópez good point re: the properties, I'll tweak that. As to the `@MappedSuperClass`, I don't have a clue TBH - I had assumed (perhaps foolishly) that it would be intelligent enough to look at all the properties on the object, no matter where they came from - The only reason for the EntityBase is that I've used a similar approach in EF which allows me to cast any entity as `EntityBase` and access common properties like `Id`, `CreatedOn`, etc... I'll do some reading on MappedSuperClass, thanks – Basic Feb 25 '13 at 16:12
  • @XaviLópez casing didn't make any difference so I've updated the Q with lowercase to avoid others spotting the same, thanks. – Basic Feb 25 '13 at 16:14
  • Indeed, in [5.1.11. Property](http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/mapping.html#mapping-declaration-property) they state "_name: the name of the property, with an initial lowercase letter._". – Xavi López Feb 25 '13 at 16:14
  • Also, looking closer, it seems likely that the error comes from mixing annotation and xml mapping configuration on that field. Try defining them all in a single way. – Xavi López Feb 25 '13 at 16:16

2 Answers2

3

You are mixing xml-mapping and annotations here. Annotations alone are enough in you case. First remove Hibernate.hbm.xml.

OrganisationNode.java

@Entity
public class OrganisationNode extends EntityBase {

    private String name;
    private String description;

    @ManyToOne
    @JoinColumn(name="ParentId")
    private OrganisationNode parent;

    @OneToMany
    private Set<OrganisationNode> children = new HashSet<OrganisationNode>();

}

EntityBase.java

@Entity
public class EntityBase {
    @Id
    @GeneratedValue
    private Long id;

}

Hibernate.config.xml

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://mysqldev:3306/SomeDb?zeroDateTimeBehavior=convertToNull</property>
    <property name="hibernate.connection.username">SomeUser</property>
    <property name="hibernate.connection.password">SomePass!</property>
    <property name="hibernate.hbm2ddl.auto">create</property>
    <property name="show_sql">true</property>

    <mapping class="com.overshare.document.entities.OrganisationNode"/>
  </session-factory>
</hibernate-configuration>
overmeulen
  • 1,158
  • 6
  • 15
1

You should either use "Hibernate.hbm.xml" or use annotations. You are trying to use both and I think that's confusing hibernate.

Everything you are doing in "Hibernate.hbm.xml" can be put into the entity classes as annotations instead. This makes things much simpler:

@Entity
@Table(name = "OrganisationNodes")
public class OrganisationNode implements Serializable {
    @Column(name = "NAME")
    private String name;

    @Column(name = "DESCRIPTION")
    private String description;
    etc.

I would get rid of EntityBase too. It doesn't give you much by the look of it, and extending base classes in Hibernate can be painful.

David Lavender
  • 8,021
  • 3
  • 35
  • 55
  • Thanks for your answer. Since you both posted at the same time and I found @overmeulen's answer slightly more detailed (eg including the Many-One relationship from the Q), I've awarded to him/her. Thank you for your help though! – Basic Feb 25 '13 at 16:45