views:

1274

answers:

6

I have a simple Class Hierarchy that I am trying to get to work with Hibernate/JPA.

Basically what I want is for the MovementData to be in its own Table with a FK to the integer id of the Main Vehicle Table in the Database.

Am I doing something wrong? How else can I accomplish something similar? I am pretty sure I am following the JPA spec. (EJB3 In Action says this should work: EJB3 In Action: @SecondaryTable

Here is a portion of the exception I am getting:

SEVERE: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: Table MOVEMENT_DATA not found
    at org.hibernate.persister.entity.JoinedSubclassEntityPersister.getTableId(JoinedSubclassEntityPersister.java:480)
    at org.hibernate.persister.entity.JoinedSubclassEntityPersister.<init>(JoinedSubclassEntityPersister.java:259)
    at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:87)
    at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:261)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1327)

Here is some of the logging info from Hibernate that pertains to the Vehicle... It looks like it is recognizing everything fine.. Then it throws the exception for some reason.

INFO: Binding entity from annotated class: com.dataobject.Vehicle
FINE: Import with entity name Vehicle
INFO: Bind entity com.dataobject.Vehicle on table VEHICLE
INFO: Adding secondary table to entity com.dataobject.Vehicle -> MOVEMENT_DATA
FINE: Processing com.dataobject.Vehicle property annotation
FINE: Processing annotations of com.dataobject.Vehicle.id
FINE: Binding column id. Unique false. Nullable false.
FINE: id is an id
FINE: building SimpleValue for id
FINE: Building property id
FINEST: Cascading id with null
FINE: Bind @Id on id
FINE: Processing annotations of com.dataobject.Vehicle.color
FINE: Binding column COLOR. Unique false. Nullable true.
FINE: binding property color with lazy=false
FINE: building SimpleValue for color
FINE: Building property color
FINEST: Cascading color with null
FINE: Processing annotations of com.dataobject.Vehicle.movementData
FINE: Binding column movementData. Unique false. Nullable true.
FINE: Binding component with path: com.dataobject.Vehicle.movementData
FINE: Processing com.dataobject.MovementData property annotation
FINE: Processing annotations of com.dataobject.MovementData.latitude
FINE: Column(s) overridden for property latitude
FINE: Binding column LATITUDE. Unique false. Nullable true.
FINE: binding property latitude with lazy=false
FINE: building SimpleValue for latitude
FINE: Building property latitude
FINEST: Cascading latitude with null
FINE: Processing annotations of com.dataobject.MovementData.longitude
FINE: Column(s) overridden for property longitude
FINE: Binding column LONGITUDE. Unique false. Nullable true.
FINE: binding property longitude with lazy=false
FINE: building SimpleValue for longitude
FINE: Building property longitude
FINEST: Cascading longitude with null
FINE: Processing annotations of com.dataobject.MovementData.speed
FINE: Column(s) overridden for property speed
FINE: Binding column SPEED. Unique false. Nullable true.
FINE: binding property speed with lazy=false
FINE: building SimpleValue for speed
FINE: Building property speed
FINEST: Cascading speed with null
FINE: Processing annotations of com.dataobject.MovementData.timeOfPosition
FINE: Column(s) overridden for property timeOfPosition
FINE: Binding column TIME_OF_POSITION. Unique false. Nullable true.
FINE: binding property timeOfPosition with lazy=false
FINE: building SimpleValue for timeOfPosition
FINE: Building property timeOfPosition
FINEST: Cascading timeOfPosition with null
FINE: Building property movementData
FINEST: Cascading movementData with null
FINE: Processing annotations of com.dataobject.Vehicle.numWheels
FINE: Binding column NUM_WHEELS. Unique false. Nullable true.
FINE: binding property numWheels with lazy=false
FINE: building SimpleValue for numWheels
FINE: Building property numWheels
FINEST: Cascading numWheels with null
INFO: Binding entity from annotated class: com.dataobject.Car
FINE: Binding column id. Unique false. Nullable false.
FINE: Subclass joined column(s) created
FINE: Import with entity name Car
INFO: Bind entity com.dataobject.Car on table CAR
FINE: Processing com.dataobject.Car property annotation
FINE: Processing annotations of com.dataobject.Car.make
FINE: Binding column MAKE. Unique false. Nullable true.
FINE: binding property make with lazy=false
FINE: building SimpleValue for make
FINE: Building property make

Vehicle is the Parent Class

/**
 * Entity implementation class for Entity: Vehicle
 *
 */
@Entity
@Table(name="VEHICLE")
@Inheritance(strategy=InheritanceType.JOINED)
@SecondaryTable(name="MOVEMENT_DATA",
            pkJoinColumns = {
                @PrimaryKeyJoinColumn(name = "ID") 
            } 
)
public class Vehicle implements Serializable {


    private int numWheels;
    private String color;
    private int id;
    private MovementData movementData;
    private static final long serialVersionUID = 1L;


    public Vehicle() {
     super();
    }   

    @Embedded
    @AttributeOverrides( {
    @AttributeOverride(
        name = "speed",
        column = @Column(name = "SPEED",
                         table = "MOVEMENT_DATA")
    ),
    @AttributeOverride(
        name = "timeOfPosition",
        column = @Column(name = "TIME_OF_POSITION",
                         table = "MOVEMENT_DATA")
    ),
    @AttributeOverride(
            name = "longitude",
            column = @Column(name = "LONGITUDE",
                             table = "MOVEMENT_DATA")
        ),
   @AttributeOverride(
            name = "latitude",
            column = @Column(name = "LATITUDE",
                             table = "MOVEMENT_DATA")
        )
})
    public MovementData getMovementData() {
     return movementData;
    }
    public void setMovementData(MovementData movementData) {
     this.movementData = movementData;
    }

    @Column(name="NUM_WHEELS")
    public int getNumWheels() {
     return this.numWheels;
    }

    public void setNumWheels(int numWheels) {
     this.numWheels = numWheels;
    }   
    @Column(name="COLOR")
    public String getColor() {
     return this.color;
    }

    public void setColor(String color) {
     this.color = color;
    }   
    @Id    
    public int getId() {
     return this.id;
    }

    public void setId(int id) {
     this.id = id;
    }

}

Car extends Vehicle

/**
 * Entity implementation class for Entity: Car
 */
@Entity
@Table(name="CAR")
public class Car extends Vehicle implements Serializable {


    private String make;
    private static final long serialVersionUID = 1L;

    public Car() {
     super();
    }   
    /**
     * @return
     */
    @Column(name="MAKE")
    public String getMake() {
     return this.make;
    }

    /**
     * @param make
     */
    public void setMake(String make) {
     this.make = make;
    }

}

MovementData is Embedded in Vehicle

@Embeddable
public class MovementData implements Serializable {


    private double speed;
    private Date timeOfPosition;
    private double latitude;
    private double longitude;
    private static final long serialVersionUID = 1L;

    public MovementData() {
     super();
    }   



    /**
     * @return
     */
    @Column(name="SPEED")
    public double getSpeed() {
     return this.speed;
    }

    /**
     * @param speed
     */
    public void setSpeed(double speed) {
     this.speed = speed;
    }   
    /**
     * @return
     */
    @Column(name="TIME_OF_POSITION")
    public Date getTimeOfPosition() {
     return this.timeOfPosition;
    }

    /**
     * @param timeOfPosition
     */
    public void setTimeOfPosition(Date timeOfPosition) {
     this.timeOfPosition = timeOfPosition;
    }   

    /**
     * @return
     */
    @Column(name="LONGITUDE")
    public double getLongitude() {
     return this.longitude;
    }

    /**
     * @param longitude
     */
    public void setLongitude(double longitude) {
     this.longitude = longitude;
    }
    /**
     * @return
     */
    @Column(name="LATITUDE")
    public double getLatitude() {
     return this.latitude;
    }

    /**
     * @param latitude
     */
    public void setLatitude(double latitude) {
     this.latitude = latitude;
    }   

}

Persistence Unit:

 <properties>
  <!-- The database dialect to use -->
  <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
  <!-- drop and create tables at deployment -->
  <property name="hibernate.hbm2ddl.auto" value="create-drop" />
  <!-- Hibernate Query Language (HQL) parser. -->
  <!-- property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" /-->
  <!-- property name="hibernate.cache.provider_class" value="org.hibernate.cache.JbossCacheProvider" /-->
  <property name ="hibernate.show_sql" value="false" />
  <property name ="hibernate.format_sql" value="false" />
  <property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" />
 </properties>
+1  A: 

From the exception you posted, it appears as if the table has not yet been created in your database ("Table MOVEMENT_DATA not found"). If you have not instructed Hibernate/JPA to alter your schema you have to manually add the table prior to running your code (I believe it is CREATE-UPDATE to instruct hibernate to perform the alter's).

Rich Kroll
I already have that in my persistence.xml
Grasper
+1  A: 

During development its often convenient to have this property enabled:

cfg.setProperty(Environment.HBM2DDL_AUTO, "update");

where cfg is my AnnotationConfiguration.

Your problem will most likely be solved by enabling this property.

Schildmeijer
I have create-drop set (see my persistence.xml above). I just tried it with update instead, and it still doesn't work with the same error.
Grasper
NOTE for anyone else with this problem: Answer was Auto Selected... This doesn't work.
Grasper
A: 

Definition of embeddable class should not reference database table:

@Embeddable
public class MovementData implements Serializable {


    private double speed;
    private Date timeOfPosition;
    private double latitude;
    private double longitude;
    private static final long serialVersionUID = 1L;

    public MovementData() {
        super();
    }   

    @Column(name="SPEED")
    public double getSpeed() {
        return this.speed;
    }

    ...

    @Column(name="TIME_OF_POSITION")
    public Date getTimeOfPosition() {
        return this.timeOfPosition;
    }

    ...

    @Column(name="LONGITUDE")
    public double getLongitude() {
        return this.longitude;
    }

    ...

    @Column(name="LATITUDE")
    public double getLatitude() {
        return this.latitude;
    }

    ...
}

Then Vehicle entity should define secondary table for embedded structure including join column:

@Entity
@Table(name="VEHICLE")
@Inheritance(strategy=InheritanceType.JOINED)
@SecondaryTable(name="MOVEMENT_DATA",
                pkJoinColumns = {
                    @PrimaryKeyJoinColumn(name = "ID") 
                } 
)
public class Vehicle implements Serializable {


    private int numWheels;
    private String color;
    private int id;
    private MovementData movementData;
    private static final long serialVersionUID = 1L;


    public Vehicle() {
        super();
    }   

    @Embedded
    @AttributeOverrides( {
        @AttributeOverride(
            name = "speed",
            column = @Column(name = "SPEED",
                             table = "MOVEMENT_DATA")
        ),
        @AttributeOverride(
            name = "timeOfPosition",
            column = @Column(name = "TIME_OF_POSITION",
                             table = "MOVEMENT_DATA")
        ),

        ... // override the rest of the attributes

    } )
    public MovementData getMovementData() {
        return movementData;
    }

    ...

    @Id    
    public int getId() {
        return this.id;
    }

    ...
}

I hope this will work for you.

grigory
Thanks for the help... Still get the same error though. I am at my wits end!
Grasper
When I run into problems like this I try to simplify playing field to make it as transparent as possible. In this case I'd take out inheritance setup from the Vehicle entity - that way you deal with one problem at the time (hopefully). After you solve problem of embeddable object in a secondary table then roll inheritance back and see how they work together.
grigory
+1  A: 

I would try breaking this down to find the issue. Try making movement data into an entity instead of an embeddable class. Make sure that it can stand on its own and then change it back to embeddable.

Although its not really the relationship that you want, you might try making MovementData the root parent and have Vehicle inherit off of MovementData. That way you would only be working with

@Inheritance(strategy=InheritanceType.JOINED)

instead of inheritance plus secondaryTable. It would simplify the relationship but still include all of the tables.

ccclark
Ah.. I think you are right.. It may be an issue with mixing @SecondaryTable with the joined Inheritance Strategy, since, from a DB perspective they look the same. This is not really an ideal solution, as I want my Java Entities to look as above.
Grasper
So you could also make it not a secondary table but just a OneToOne relationship between Vehicle and MovementData. With the right cascades it would behave the same.
ccclark
A: 

Connect to your database using your appropriate db client (Query Browser, MS SQL Managment Studio, etc) to verify whether or not the tables do, in fact, exist.

You may also want to insert a breakpoint in your code so that you can see exactly what the database looks like at the moment before it's throwing this error.

Try setting the hibernate.hbm2ddl.auto value to "create" as below, and also change the setting so that it prints out the SQL so you can see what it's attempting:

<props>
  <!-- some possible values: create, create-drop, update -->
  <prop key="hibernate.hbm2ddl.auto">update</prop>
  <prop key="hibernate.show_sql">true</prop>
  ....
<props>

Let me know what you see in your db.

Cuga
It ends up not creating anything in the actual DB when I set that to create. It throws that exception before that point. I added some more of the logging info to my post above.
Grasper
Why not try adding the Id's column name to Id field of Vehicle, like so: @Id @Column(name="ID") public int getId() { return this.id; }
Cuga
A: 

I just ran into this. Has anyone found an answer? It looks like it might be a hibernate bug

[http://opensource.atlassian.com/projects/hibernate/browse/HHH-4250][1]