我有一个简单的类层次结构,我试图使用Hibernate / JPA。
基本上我想要的是MovementData在其自己的表中,其FK为数据库中主车辆表的整数id。
我做错了吗?我怎样才能完成类似的事情呢? 我很确定我遵循JPA规范。 (EJB3 In Action说这应该有效:EJB3 In Action: @SecondaryTable
这是我得到的例外的一部分:
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)
以下是来自Hibernate的一些与Vehicle有关的日志信息...看起来它正在识别一切正常..然后由于某种原因抛出异常。
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
车辆是父类
/**
* 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;
}
}
汽车延伸车辆
/**
* 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嵌入车辆
@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;
}
}
持久单元:
<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>
答案 0 :(得分:1)
在开发过程中,启用此属性通常很方便:
cfg.setProperty(Environment.HBM2DDL_AUTO, "update");
其中cfg是我的AnnotationConfiguration。
您的问题最有可能通过启用此属性来解决。
答案 1 :(得分:1)
我会尝试将其分解以找到问题。尝试将移动数据转换为实体而不是嵌入类。确保它可以自行站立,然后将其更改为可嵌入。
虽然它不是你想要的关系,但你可以尝试将MovementData作为根父,并使Vehicle继承MovementData。那样你只会使用
@Inheritance(strategy=InheritanceType.JOINED)
而不是继承加上secondaryTable。它会简化关系,但仍然包括所有表。
答案 2 :(得分:1)
我觉得这样做太迟了,但在寻找别的东西时我偶然发现了这个问题。
问题是Embeddable类没有映射到表 - Embeddable对象在数据库中没有标识。
这就是没有生成MovementData表的原因。
我认为你已经混淆了嵌入式的含义。正如前一位评论者所提到的,Vehicle和MovementData应该处于OneToOne关系中,并且应该删除嵌入式注释。您可能需要Cascade Remove规则以确保在移除车辆时,MovementData也是如此。
答案 3 :(得分:0)
从您发布的例外情况看,似乎尚未在您的数据库中创建表(“未找到表MOVEMENT_DATA”)。如果您没有指示Hibernate / JPA更改模式,则必须在运行代码之前手动添加表(我相信它是CREATE-UPDATE以指示hibernate执行更改)。
答案 4 :(得分:0)
embeddable class 的定义不应该引用数据库表:
@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;
}
...
}
然后,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")
),
... // override the rest of the attributes
} )
public MovementData getMovementData() {
return movementData;
}
...
@Id
public int getId() {
return this.id;
}
...
}
我希望这对你有用。
答案 5 :(得分:-1)
使用适当的数据库客户端(查询浏览器,MS SQL Managment Studio等)连接到您的数据库,以验证这些表是否确实存在。
您可能还希望在代码中插入一个断点,以便在它抛出此错误之前,您可以准确地看到数据库的样子。
尝试将hibernate.hbm2ddl.auto值设置为“create”,如下所示,并更改设置以便打印出SQL,以便您可以看到它正在尝试的内容:
<props>
<!-- some possible values: create, create-drop, update -->
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
....
<props>
让我知道您在数据库中看到的内容。