单表继承WITHOUT Discriminator列

时间:2011-07-04 14:31:46

标签: java hibernate jpa

亲爱的同志们,早上好,

这开始变得烦人 - 一件简单的事情,但几个小时的斗争,我变老了吗?

我正在尝试使用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本身,因为它是被用于其他地方的坚持。

5 个答案:

答案 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)
    )