【问题标题】:Single Table Inheritance WITHOUT Discriminator columnSingle Table Inheritance WITHOUT Discriminator 列
【发布时间】:2011-07-04 14:31:45
【问题描述】:

早安,我亲爱的同志们,

这开始变得烦人了 - 一件简单的事情,但经过数小时的努力,我会变老吗??

我正在尝试使用 Hibernate 的 JPA 将两个类映射到一个表。这个想法是在父类中只有一小部分列,在子类中设置更大/完整。不涉及 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,因为它正在用于其他地方的持久性。

【问题讨论】:

  • 只是猜测...从父类中删除@Entity@Table?你不是说要分开存放吧?

标签: java hibernate jpa


【解决方案1】:

@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
}

【讨论】:

  • 你会如何组织你的映射?
  • @MappedSuperclass@MappedSuperClass ?
  • 不,如果您还需要子实体成为实体,则 MappedSuperclass 不起作用。想象一下,您将“PersonRef”和“Person”作为指向同一个表/行的两个独立实体。 “PersonRef”仅包含 id 和名称,“Person”将映射所有表字段。拥有这样一个“PersonRef”实体的目的是能够与子实体建立 JPA 关系。所以我的地址实体可以指向“PersonRef”而不是指向完整的“Person”
  • @PapickG.Taboada 然后使用实体继承。但这是一个与 OP 不同的问题,谁想要两个独立的实体。
【解决方案2】:

有几种方法,每种方法都有自己的注意事项。

1) 添加如下注释:

@DiscriminatorFormula("0")
@DiscriminatorValue("0")
class BaseClass{  }

@DiscriminatorValue("00")
class SubClass extends BaseClass{  }

其中子类鉴别器的值必须与基类不同,但在传递给 Integer.valueOf(String s) 方法时也计算为相同的值。

警告 - 如果您从基类的 Hibernate 返回一个对象,然后在调用子类类型时再次调用,您将收到一个错误,抱怨加载的对象属于错误的类。如果您首先调用子类查询,但是基类调用将返回子类。

2) 使用数据库中的视图来映射表,并将其用作子类的表。事实上,它可以是任何其他匹配列映射的类,因为 Hibernate 认为它是一个完全独立的表。

警告 - 您可能会将同一行实例化为两个不同的对象,这些对象不会同步,并可能导致数据库更新冲突/丢失。

最好为会话坚持使用一种类型,并且可以通过使用覆盖所需类的 DiscriminatorValue 以匹配常量 Discriminator'Formula' 值的实体映射 xml 文件来处理而没有运行时风险传入初始配置。

【讨论】:

    【解决方案3】:

    使用有限的列集创建表视图,并将第二个类映射到该类。使用有限的列集定义一个接口,并让两个类都实现该接口。这可能会为您提供大约 95% 的需求。如果需要,创建方法来定义两者之间的相等性以及能够将较大的类(通过构造函数?)转换为较小的类。

    【讨论】:

      【解决方案4】:

      您必须为两个实体选择一种继承类型。

      您尝试做的事情是不合适的,因为 hibernate 不知道要实例化哪些对象。

      如果您只是需要一个对象具有更少的字段,那么不要将它映射为一个实体 - 只需提供一个构造函数来复制其他类的所有字段。

      【讨论】:

      • 当涉及到关系时,拥有一个映射到子集的实体很有趣。我不明白 - 为什么 Hibernate 不知道?我有确实请求一个或另一个的 DAO 和映射。
      【解决方案5】:

      如果您不想添加自动 dtype 列,则应通过 @DiscriminatorFormula 定义自己的鉴别器

      @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)
          )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-03-21
        • 2023-03-12
        • 1970-01-01
        • 2022-12-01
        • 2022-12-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多