JPA实体:继承和一对一关系不能同时工作

时间:2014-12-23 16:36:57

标签: java hibernate jpa ejb

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

我的目标是查询TableB,并从中获取TableA1或TableA2的信息,具体取决于类型。

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

在TableB中,我有两个组合表示外键的列:type和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)
 );

1 个答案:

答案 0 :(得分:0)

更新回答:

已更新以匹配数据库

您可以使用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));