Hibernate:加入多键表的一个键

时间:2010-09-17 07:56:15

标签: java hibernate orm hibernate-onetomany

我有一个表类别和一个表TranslatableText。类别是这样的

create table Category (
  id int not null,
  parent_id int default 0,
  TranslatableDescriptionId int default 1,
  primary key(id));

create table TranslatableText (
  id int not null,
  lang enum ('NO','EN','FR'),
  text mediumtext,
  primary key(id, lang));

在我的Category实体中,我定义了一个映射:

@Fetch(FetchMode.SUBSELECT)
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
@OneToMany(fetch=FetchType.LAZY)
@JoinColumn(name="TranslatableDescriptionId")
@ForeignKey(name="FK_TranslatableTextId")
private Set<TranslatableText> translatableText;

但是当它执行时,它会尝试访问TranslatableDescriptionId,而不是id。即使TranslatableText实体已经定义了

@Id
@Column(name = "id", nullable = false)
private Integer id;

@Id
@Column(name = "lang", nullable = false)
@Enumerated(EnumType.STRING)
private String lang;

@Column(name = "text", length = 400, nullable = false)
private String text;

选择了错误名称的查询:

选择translatab0_.TranslatableDescriptionId作为Translat4_13_1_,translatab0_.id作为id1_,translatab0_.lang作为Lang1_,translatab0_.id作为id22_0_,translatab0_.lang作为Lang22_0_,translatab0_.text作为Text22_0_来自tblTranslateableText translatab0_其中translatab0_.TranslatableDescriptionId in('126 ','119','103','116','121','107','113','101','109','105','123','106','125', '124','114')

如果我将映射@JoinColumn更改为

@JoinColumn(name="TranslatableDescriptionId", referencedColumnName="id")

加载我的应用时出现以下错误:

org.hibernate.MappingException:无法在org.hibernate.mapping.Table(Category)及其相关的supertables和secondary tables中找到具有逻辑名称:id的列

为了更好的衡量,我也尝试过:

@JoinColumn(name="id", referencedColumnName="TranslatableDescriptionId")

这给了我错误:

org.hibernate.MappingException:无法找到具有逻辑名的列:org.hibernate.mapping.Table(Category)中的TranslatableDescriptionId及其相关的supertables和secondary tables

对我应该做什么的任何建议?我真的希望Category的translateableText包含其描述的所有翻译,所以我真的想加入Category.TranslatableDescriptionId == TranslatableText.id

UPDATE1: TranslatableText被许多实体使用,因此在其中放入categoryId并反转关系不是一种选择。

UPDATE2: 我能够加载它说@JoinColumn(name="id"),但这导致了Hibernate中的ClassCastException,它不是将一个Integer作为键,而是一个包含单个Integer作为键的Array。这不能成为一个字符串,因此适当的SQL。所以它可能仍然不是我想要的映射

干杯

的Nik

1 个答案:

答案 0 :(得分:2)

这种映射是可行的,但不是很方便,因为你必须手动管理TranslatableText的身份(这就是为什么Hibernate抱怨非映射列TranslatableDescriptionId):

public class Category implements Serializable {
    ...
    private Long translatableDescriptionId;

    @OneToMany
    @JoinColumn(name="id", referencedColumnName="TranslatableDescriptionId") 
    private Set<TranslatableText> translatableText;
    ...
}

因此,您需要为translatableDescriptionId的所有“目标”(您所说的类别,项目,文件夹)手动分配唯一的TranslatableText,并手动将此值设置为id在保留之前TranslatableText(您不能只将TranslatableText添加到Set)。

-

然而,更方便的设计是引入一个中间实体来保持所有转换的特性附加到特定目标:

public class Category {
    ...
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "targetId")
    private TranslationTarget target;
}

public class TranslationTarget {
    @Id @GeneratedValue
    private Long id;

    @OneToMany
    @JoinColumn(name = "targetId")
    private Set<TranslatableText> texts;
}

-

create table Category (              
  targetId int,
  ...);        

create table TranslationTargets (
  id int primary key
);      

create table TranslatableText (              
  targetId int not null,              
  lang enum ('NO','EN','FR'),              
  text mediumtext,              
  primary key(targetId, lang));