Hibernate并没有PK

Sch*_*jer 52 java database hibernate jpa

是否可以创建一个@Entity不包含主键/ Id 的表(来自JPA注释的Hibernate )?

我知道这不是一个好主意; 表应该有一个主键.

awi*_*ied 50

罗杰的自我回答是正确的.详细说明一下是什么意思(我一开始并不清楚它,并认为这会有所帮助):

假设你有一个表Foo如下:

TABLE Foo (
bar varchar(20),
bat varchar(20)
)
Run Code Online (Sandbox Code Playgroud)

通常,您可以编写带有Annotations的类来使用此表:

// Technically, for this example, the @Table and @Column annotations 
// are not needed, but don't hurt. Use them if your column names 
// are different than the variable names.

@Entity
@Table(name = "FOO")
class Foo {

  private String bar;
  private String bat;


  @Column(name = "bar")
  public String getBar() {
   return bar;    
  }

  public void setBar(String bar) {
   this.bar = bar;    
  }

  @Column(name = "bat")
  public String getBat() {
   return bat;    
  }

  public void setBat(String bat) {
   this.bat = bat;    
  }

}
Run Code Online (Sandbox Code Playgroud)

..但是,该死的.这个表没有任何我们可以用作id的东西,它是我们用于[插入重要业务功能]的遗留数据库.我不认为他们会让我开始修改表格以便我使用hibernate.

相反,您可以将对象拆分为休眠可操作的结构,该结构允许将整行用作键.(当然,这假设行是唯一的.)

这样将Foo对象拆分为两个:

@Entity
@Table(name = "FOO")
class Foo {

  @Id
  private FooKey id;

  public void setId(FooKey id) {
    this.id = id;
  }

  public void getId() {
    return id;
  }
}
Run Code Online (Sandbox Code Playgroud)

@Embeddable
class FooKey implements Serializable {
  private String bar;
  private String bat;

  @Column(name = "bar")
  public String getBar() {
   return bar;    
  }

  public void setBar(String bar) {
   this.bar = bar;    
  }

  @Column(name = "bat")
  public String getBat() {
   return bat;    
  }

  public void setBat(String bat) {
   this.bat = bat;    
  }
Run Code Online (Sandbox Code Playgroud)

}

..那应该是它.Hibernate将使用Embeddable键作为其所需的身份,您可以正常拨打电话:

Query fooQuery = getSession().createQuery("from Foo");
Run Code Online (Sandbox Code Playgroud)

希望这有助于第一次使用这个工作.

  • 我想提一下,因为我刚遇到这个问题,如果你用于复合键的那些列中的任何一个是NULL,那么Hibernate将返回null对象.我从一个视图中拉出所有内容,其中一列全部为空,因此hibernate返回一个包含正确数量项的列表,但所有项都为null.在我的情况下,我无法修改字段,所以我只是从密钥中删除它. (19认同)

小智 45

使用以下代码; Hibernate没有自己的逻辑来区分重复记录

如果这种方法存在任何问题,请告诉我

@Entity @IdClass(Foo.class)
class Foo implements Serializable {
  @Id private String bar;
  @Id private String bat;

  public String getBar() {
   return bar;    
  }

  public void setBar(String bar) {
   this.bar = bar;
  }


  public String getBat() {
   return bat;    
  }

  public void setBat(String bat) {
   this.bat = bat;    
  }
}
Run Code Online (Sandbox Code Playgroud)

  • @HoàngLong:正如[@Casey](http://stackoverflow.com/questions/767277/hibernate-and-no-pk#comment4613715_1776125)所说,你的列不能为NULL. (3认同)
  • 这是最好的答案.它使用自己作为ID类,不必做两个单独的类.我将Id注释移动到我的getter,因为它们具有所需的Column映射.它的工作完美,并没有打破缓存.+1 (2认同)
  • 至少Hibernate-3.5.2不能完全使用这种非常好的方法。在我尝试检索具有空列的实体之前,一切对我来说似乎都正常。即使我没有将它们标记为@ Id,Hibernate仍将ALL列用作主键,并且无法处理主键中的空值。这导致检索结果中的对象为空。将所有@Id字段复制到静态内部类中,然后再次在其中生成getter / setter以及equals()和hashCode()方法,并将此内部类用作@IdClass来完成我的工作。 (2认同)

Sch*_*jer 9

我发现它不可能这样做.对那些使用遗留系统的人来说,运气不好.

如果您进行逆向工程(从现有JDBC连接创建JPA注释实体),该表将创建两个Java类,一个实体和一个字段; id,以及一个包含您关系中所有列的可嵌入ID.


Rud*_*udi 9

我发现这个技巧有效:

<id column="ROWID" type="string" />
Run Code Online (Sandbox Code Playgroud)


小智 5

虽然 ROWID 是一个伪列,但由于 ROWID 对应的是一个 ROW 的物理地址,所以它是检索任何行数据的最快方法。由于@Id 用于唯一标识对象,而 ROWID 在表中是唯一的,我们可以利用它来解决我们正在讨论的问题。实际上,如果我们不需要任何有意义的唯一标识符,ROWID 是使用 @Id 注释的最佳列,因为它对应于行的物理地址。以下代码对我有用。 @Id @Column(name = "ROWID") private String Id;