我有以下两个表:

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;
}


现在缺少两件事:


Map<String, B> bMap的注释。我只是不知道应该使用@MapKey还是@MapKeyColumn以及如何映射到该复合键。如果我应该/必须使用@OneToMany
当然,B类需要一个组合键。我应该使用@EmbeddedId还是@IdClass


您能为这种情况提供一些示例代码吗?

谢谢!

最佳答案

底部的工作解决方案



我想,我现在已经设法将所有东西放在一起。至少生成的SQL表看起来正确,尽管我仍然必须弄清楚如何完成级联保存...

@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(...)时,休眠提供:

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


哪个是对的。

但是,如果我调用aEntity.getBMap(),则即使我只想使用aEntity.getBMap().put("EN", someBObject)而不希望从中读取任何数据,它总是会获取整个地图。但是现在还可以。

现在,我只想弄清楚如何使级联保存起作用。当做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(...)


休眠:从* id =?的A中选择*。


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


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


aRepository.save(a)


休眠:插入B(a_id,locale,z)值(?,?,?)

10-06 04:34