【问题标题】:JPA entities: inheritance and one-to-one relationship not working simultaneouslyJPA 实体:继承和一对一关系不能同时工作
【发布时间】:2014-12-23 16:36:56
【问题描述】:

我有以下方案:TableA1 和 TableA2 存在于数据库中,每个都由一个实体 bean 表示。由于它们是相关的,我创建了一个抽象类(TableA,它是一个实体,但在数据库中不存在),其中两个实体都继承自这个类。另外,TableA 与TableB 是一对一的关系。

我的目标是查询 TableB 并根据类型从那里获取 TableA1 或 TableA2 的信息。

TableA1和TableA2各有一个id(每个表都会自动生成一个序号,所以可能会有重复)。

在 TableB 中,我有两列组合起来表示外键:类型和 id。 Type = 1 表示 id 在 TableA1 中。与 TableA2 类似。

我的问题是我不知道如何将这两列定义为外部外键。 这就是我所拥有的:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn(name="type")
public abstract class TableA { 

    @Id
    @Column(name = "type")
    protected int type;


    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    protected int id;

    @Column(name = "name")
    private String name;

    // Getters and setters

}


@Entity
@DiscriminatorValue("1")
@Table (name="tableA1")
public class TableA1 extends TableA {

    @Column(name="col1")
    private String col1;

    // Getters and setters

}


@Entity
@DiscriminatorValue("2")
@Table (name="tableA2")
public class TableA2 extends TableA {

    @Column(name="col2")
    private String col2;

    // Getters and setters
}


@Entity
@Table (name="tableB")
public class TableB {

    @Id 
    @Column(name="someId")
    private Integer someId;


    @Column(name="type")
    private int type;

    @Column(name="id")
    private Integer id;   


    @OneToOne(optional = false, cascade = CascadeType.ALL)
    @JoinColumns({    
        @JoinColumn(name = "type"),
        @JoinColumn(name = "id" )
      })
    private TableA tableA;

    // Getters and setters

}

更新

我在寻找不可能的事吗?这是我发现的:

在每类表的层次结构中与非叶类的多态关系有很多限制。当具体子类未知时,相关对象可能位于任何子类表中,从而无法通过关系进行连接。这种模糊性也会影响身份查找和查询;这些操作需要多个 SQL SELECT(每个可能的子类一个)或一个复杂的 UNION。

更新 2

TableA1、TableA2、TableB已经存在在数据库中,结构如下:

 CREATE TABLE TableA1 (
   surrogate_key int AUTO_INCREMENT,
   some_char char(30),
   PRIMARY KEY (surrogate_key)
 );

CREATE TABLE TableA2 (
   surrogate_key int AUTO_INCREMENT,
   some_int int,
   PRIMARY KEY (surrogate_key)
);

CREATE TABLE TableB (
   surrogate_key int AUTO_INCREMENT,
   type int,  // if type=1, sk represents the surrogate_key of tableA1
              // if type=2, sk represents the surrogate_key of tableA2
   sk int,
   description varchar(200),
   PRIMARY KEY (surrogate_key)
 );

【问题讨论】:

  • 也许可以添加一个 EER 图,这样我们就可以理解这个复杂的休眠问题。
  • 是的,如果 type=1,则 sk 指向 TableA1,如果 type=2,则 sk 指向 TableA2,如果 type = 0,则 sk = 0。这就是我尝试使用 @987654323 的原因@
  • 我只见过 Discriminator 用于单表继承。您的表TableA1TableA2 不是缺少类型列吗?还是 Hibernate 只是在内部使用它们?
  • 如果我将 type 列添加到 TableA1 和 TableA2 那么这些列将具有常量值(分别为“1”和“2”)。我试图避免这种情况。
  • 您的限制是什么?表结构是否已冻结或 JPA 实体代码是否已冻结?你想达到什么目的?

标签: java hibernate jpa ejb


【解决方案1】:

更新答案:

已更新以匹配数据库

您可以使用 getDiscriminatorValue() 来访问 DiscriminatorValue。

像这样定义映射:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.INTEGER)
public abstract class TableA implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.TABLE)
  @Column(name = "surrogate_key")
  protected int id;

  @Id
  @Column(name = "type")
  protected int type;

  // Constructors & getters/setters

  @Transient
  public String getDiscriminatorValue() {
    DiscriminatorValue val = this.getClass().getAnnotation(DiscriminatorValue.class);
    return val == null ? null : val.value();      
  }
}        


@Entity
@DiscriminatorValue("1")
public class TableA1 extends TableA {

  @Column(name = "some_char", length = 1)
  private char someChar;

  // Constructors & getters/setters & toString/equals
}


@Entity
@DiscriminatorValue("2")
public class TableA2 extends TableA {

  @Column(name = "some_int")
  private int someInt;

  // Constructors & getters/setters & toString/equals
}

@Entity
public class TableB implements Serializable {
  @Id
  @GeneratedValue
  @Column(name = "surrogate_key")
  private int id;

  @OneToOne
  @Cascade(value = CascadeType.SAVE_UPDATE)
  @JoinColumns({@JoinColumn(name = "sk", referencedColumnName = "surrogate_key"),
  @JoinColumn(name = "type", referencedColumnName = "type")})
  private TableA tableA;

  @Column(name = "description", length = 200)
  private String description;

  // Constructors & getters/setters & toString/equals

}

并像这样查询:

newSession.createQuery("from TableB tb where tb.tableA.type=:type order by tb.id asc").setParameter("type", 1));

【讨论】:

  • 感谢您的回答。我试图避免使用InheritanceType.SINGLE_TABLE,因为 TableA1 和 TableA2 已经存在于数据库中,并且我不想将它们合并到一个表中,因为它们的结构差异很大。请查看更新 2
  • hibernate_sequences 的目的是什么?我试图避免向 TableA1 和 TableA2 添加类型列,因为这些列将包含一个常量值。
  • 它用于生成主键(strategy = GenerationType.TABLE) 我需要使用这个策略,否则会给我错误。不要太在意它。我正在使用 HSQLDB 和 Hibernate 工具来生成表。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多