这开始变得烦人 - 一件简单的事情,但几个小时的斗争,我变老了吗?
我正在尝试使用JPA by Hibernate将两个类映射到单个表。我们的想法是在父类中只有一小部分列,在子类中只有更大/全集。没有涉及TABLE继承,只有类继承。 怎么能实现呢?
这样做不起作用:
@Entity
@Table(name = "the_table")
class Parent implements Serializable {
}
@Entity
@Table(name = "the_table")
class Child extends Parent implements Serializable {
}
Hibernate假定默认继承策略为InheritanceType.SINGLE_TABLE,并且默认情况下正在寻找鉴别器列 - DTYPE。但是等等 - 没有表继承,鉴别器列没有出现。
我还看了一下PolymorphismType.EXPLICIT没有任何区别。堆栈跟踪是:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'apprentice0_.DTYPE' in 'where clause'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1052)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3597)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3529)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1990)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2151)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2625)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2281)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1808)
at org.hibernate.loader.Loader.doQuery(Loader.java:697)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1881)
是的,还有一件事:
@MappedSuperclass
和@Embeddable
没有用,因为它们不能与@Entity
一起使用 - 父类必须是@Entity
本身,因为它是被用于其他地方的坚持。
答案 0 :(得分:20)
@MappedSuperclass
是必须使用的注释。如果同一个类既是映射的超类又是实体,那么只需将其拆分为两个类:
@MappedSuperclass
public class Parent {
// ...
}
@Entity
public class ParentEntity extends Parent {
// no code at all here
}
@Entity
public class Child extends Parent {
// additional fields and methods here
}
答案 1 :(得分:7)
有几种方法都有自己的警告。
1)添加注释如下:
@DiscriminatorFormula("0")
@DiscriminatorValue("0")
class BaseClass{ }
@DiscriminatorValue("00")
class SubClass extends BaseClass{ }
其中子类鉴别符值必须与基类不同'但是在传递给Integer.valueOf(String s)方法时也会计算相同的值。
警告 - 如果从基类的Hibernate返回一个对象,然后在调用子类类型时再次返回,则会收到错误,抱怨加载的对象是错误的类。如果先调用子类查询,则基类调用将返回子类。
2)使用数据库中的视图映射表并将其用作子类的表。事实上,它可以是任何其他类匹配列映射,因为Hibernate认为它是一个完全独立的表。
警告 - 您可能会将同一行实例化为两个不同的对象,这些对象将无法同步,并可能导致数据库更新冲突/丢失。
最好坚持使用一种类型的会话,并且可以通过使用覆盖所需类的DiscriminatorValue的实体映射xml文件以匹配常量判别符来处理而无需运行时风险。式'您可以传递给初始配置的值。
答案 2 :(得分:2)
使用有限的列集来查看表,并将第二个类映射到该表。使用有限的列集定义接口,并让两个类都实现接口。这可能会让你获得95%的需求。如果需要,创建方法来定义两者之间的相等性,以及能够将较大的类(通过构造函数?)转换为较小的类。
答案 3 :(得分:1)
您必须为两个实体选择继承类型。
你要做的是不合适的,因为hibernate不会知道要实例化的对象。
如果您只需要一个对象拥有更少的字段,那么不要将其映射为实体 - 只需提供一个复制其他类中所有字段的构造函数。
答案 4 :(得分:0)
如果您不想添加自动dtype列,则应通过@DiscriminatorFormula定义自己的Discriminator
@Entity
@Table(name = "CS_CUSTOMER")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorFormula("case when id < 3 then 'VIP' else 'Customer' end")
public class Customer extends BaseEntity {
...
@Entity
public class VIP extends Customer {
...
“鉴别符”名称默认为实体类名称,如果要更改它,请使用
@DiscriminatorValue("VIP")
从休眠状态登录
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate:
create table cs_customer (
id bigint not null,
create_user_id bigint,
first_name varchar(255),
last_name varchar(255),
primary key (id)
)