使用实体</string,>中的复合键映射<string,entity =“”>

时间:2014-03-22 04:56:43

标签: java hibernate jpa map jpa-2.0

我有以下两张表:

TABLE A:
  INT      id
  VARCHAR  x
PRIMARY KEY (id)

TABLE B:
  INT      a_id
  VARCHAR  locale
  VARCHAR  z
PRIMARY KEY (a_id, locale)

它基本上是一个简单的OneToMany关系。表B包含表a_id中引用行的ID(A)加上locale。这意味着:A中的每个条目都可以在表0..*中包含B个条目,每个条目都具有不同的locale值。

我有以下两个类,它们应代表这些表:

@Entity
@Table(name="A")
class A {
  @Id
  @Column(name="id")
  int id;

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

  @OneToMany(mappedBy="a") // ???
  @MapKey... // ???
  Map<String, B> bMap;
}

@Entity
@Table(name="B")
class B {
  @ManyToOne
  @JoinColumn(name="a_id")
  A a;

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

  @Column(name="z")
  String z;
}

现在缺少两件事:

  1. Map<String, B> bMap的注释。我只是不知道是否应该使用@MapKey@MapKeyColumn以及如何映射到该复合键。如果我应该/必须使用@OneToMany

  2. B类当然需要一个复合键。我应该使用@EmbeddedId还是@IdClass

  3. 您能为此方案提供一些示例代码吗?

    谢谢!

1 个答案:

答案 0 :(得分:1)

底部的工作解决方案


我想,我现在已经把事情放在了一起。至少生成的SQL表看起来是正确的,但我仍然需要弄清楚如何完成Cascaded Saving ......

@Entity
@Table(name="A")
public class A {
   @Id @GeneratedValue(strategy=GenerationType.AUTO)
   long id;

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

   @OneToMany(mappedBy="id.a", cascade=CascadeType.ALL, orphanRemoval=true)
   @MapKey(name="id.locale")
   Map<String, B> bMap = new HashMap<String, B>();
}

@Entity
@Table(name="B")
public class B {
   @EmbeddedId
   BPK id;

   @Column(name="z")
   String z;
}

@Embeddable
public class BPK implements Serializable {
   @ManyToOne
   @JoinColumn(name="a_id")
   A a;

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

   // equals + hashcode
}

致电aRepository.findById(...) Hibernates时:

Hibernate: select * from A a where a.id=?

这是正确的。

但是,如果我调用aEntity.getBMap(),它总是会获取整个地图,即使我只想使用aEntity.getBMap().put("EN", someBObject)并且不想从中读取任何数据。但现在没关系。

现在我只想弄清楚如何让Cascaded Saving工作。在做aEntity.getBMap().put("EN", someBObject); aRepository.save(eEntity);时我得到了

org.hibernate.id.IdentifierGenerationException: null id generated for:class B

我想我只是错过了@EmbeddedId或其字段的一些制定者。


最终解决:

级联保存以某种方式无法与@EmbeddedId复合键一起使用。所以我想到了它并想通了,我可以改为使用@ElementCollection:)

所以这就是我最终做的事情:

@Entity
@Table(name="A")
public class A {
   @Id @GeneratedValue(strategy=GenerationType.AUTO)
   long id;

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

   @ElementCollection
   @CollectionTable(name="B", joinColumns=@JoinColumn(name="a_id"))
   @MapKeyColumn(name="locale")
   Map<String, B> bMap = new HashMap<String, B>();
}

@Embeddable
public class B {
   @Column(name="z")
   String z;
}

休眠输出:

A a = aRepository.findById(...)

  • 休眠:从A中选择*,其中id =?

a.getBMap().put("EN", someBObject)

  • 休眠:从B中选择*,其中a_id =?

aRepository.save(a)

  • Hibernate:插入B(a_id,locale,z)值(?,?,?)