2010-07-19 67 views
2

我有一个关于JPA中实体声明的简单问题。 我有一个有2个外键的实体,它们不为null,并形成一个uniqueConstraint。首先,我在考虑一个由两个外键组成的组合键,但我听说这是一个传统设计,而不是推荐的设计新表的方式。如何根据JPA/Hibernate中的两个外键生成id?

所以我很感兴趣,如果Hibernate/JPA可以根据这两个外键自动生成id。比方说,我有以下实体:

@Entity 
public class Foo { 
    @ManyToOne 
    private Bar bar; 
    private int i; 
} 

(我省略不为空和的UniqueConstraint标签,使代码更易读)

我知道我可以简单地添加一个id字段,与GeneratedValue,让我数据库生成密钥(在我的例子中,使用auto_increment的MySQL),但这对我来说似乎效率低下,因为它涉及查询数据库并要求它生成唯一的id值。

是否有一种方法,基于“Bar”类的id和整数“i”的值生成一个不是复合(即int或long类型)的id,因为它们有两个值已经形成一个独特的约束?

回答

5

您可能想查看“Java Persistence with Hibernate”的第7章。

您可以组合键模型作为嵌入式

import javax.persistence.*; 
import java.io.Serializable; 

@Entity 
public class Foo { 

    @Embeddable 
    public static class Id implements Serializable { 
     @Column(name = "bar_id_col") 
     private Long barId; 

     @Column(name = "i_col") 
     private int i; 

     public Id() { 
     } 

     public Id(Long barId, int i) { 
      this.barId = barId; 
      this.i = i; 
     } 

     @Override 
     public boolean equals(final Object o) { 
      if (this == o) { 
       return true; 
      } 
      if (!(o instanceof Id)) { 
       return false; 
      } 

      final Id id = (Id) o; 

      if (i != id.i) { 
       return false; 
      } 
      if (barId != null ? !barId.equals(id.barId) : id.barId != null) { 
       return false; 
      } 

      return true; 
     } 

     @Override 
     public int hashCode() { 
      int result = barId != null ? barId.hashCode() : 0; 
      result = 31 * result + i; 
      return result; 
     } 
    } 

    @EmbeddedId 
    private Id id = new Id(); 

    @ManyToOne 
    @JoinColumn(name = "bar_id_col", insertable = false, updatable = false) 
    private Bar bar; 

    private int i; 

    public Foo() { 
    } 

    public Foo(Bar bar, int i) { 
     // set fields 
     this.Bar = bar; 
     this.i=i; 
     // set identifier values 
     this.id.barId = bar.getId(); 
     this.id.i = i; 
    } 

} 

在这里,我认为酒吧的样子:

import javax.persistence.Entity; 
import javax.persistence.Id; 

@Entity 
public class Bar { 

    @Id 
    Long id; 

    public Long getId() { 
     return id; 
    } 

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

注意,这个映射bar_id_col两次。这是在第二个参考中insertable = false,updatable = false的原因。

这很棘手,但如果你真的想这样做,这是可能的。你好, J.

+0

谢谢,伙计!这正是我需要的。 – eold 2010-07-19 12:22:55

+0

非常好。谢谢! 通过谷歌搜索找到一个体面的例子几乎是不可能的。显然,除了这一个。 – kaqqao 2013-09-08 10:45:29

1

我认为'低效率'非常小,在99.99%的情况下它可以被忽略。

对于支持自动增量列的数据库,没有额外的往返时间要求它生成ID。对于不支持自动增量列的数据库(例如Oracle),Hibernate会进行一些优化,以减少用于生成ID的DB访问(例如,获取序列值,乘以50并将结果中的下一个50值用作新实体的ID )

1

我想你应该在这里重新考虑你的设计;有一个组合键或更好的Id可能更有意义。

从外键生成主键值的原理可能会适得其反。这是因为主键不能被修改 - 如果其中一个外键值发生了变化呢?主键值是否应该重新生成?并且其他表中的列引用是否应该被修改?在任何情况下,JPA都要求不要更改主键,所以最好使用自然键或代理键。

编写生成器的努力,最好花在确保模型是正确的。

+0

这些外键实际上不能改变。 – eold 2010-07-19 12:06:13