Hibernate:与多键表的键之一连接

发布于 2024-09-24 00:29:37 字数 2355 浏览 2 评论 0原文

我有一个表 Category 和一个表 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));

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

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

选择了不正确名称的查询:

select translatab0_.TranslatableDescriptionId as Translat4_13_1_、translatab0_.id as id1_、translatab0_.lang as Lang1_、translatab0_.id as id22_0_、translatab0_.lang as Lang22_0_、translatab0_.text as来自 tblTranslateableText translatab0_ 的 Text22_0_ 其中 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) 中的 id 及其相关的超级表和辅助表

为了更好的措施,我也尝试过:

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

这给了我错误:

org.hibernate.MappingException:无法找到具有逻辑名称的列:TranslatableDescriptionId在 org.hibernate.mapping.Table(Category) 及其相关的超级表和辅助表中

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

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

更新2: 我能够加载它说 @JoinColumn(name="id"),但这导致了 Hibernate 中的 ClassCastException,其中它没有一个 Integer 作为键,而是一个包含单个值的数组整数作为键。无法将其转换为字符串,因此无法转换为正确的 SQL。所以这可能仍然不是我想要的映射

Cheers

Nik

I've got a table Category and a table TranslatableText. The category is like this

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

In my Category entity I've defined a mapping:

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

But when it executes, it tries to access TranslatableDescriptionId, not id. Even if the TranslatableText entity has defined

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

The query with the incorrect name selected:

select translatab0_.TranslatableDescriptionId as Translat4_13_1_, translatab0_.id as id1_, translatab0_.lang as Lang1_, translatab0_.id as id22_0_, translatab0_.lang as Lang22_0_, translatab0_.text as Text22_0_ from tblTranslateableText translatab0_ where translatab0_.TranslatableDescriptionId in ('126', '119', '103', '116', '121', '107', '113', '101', '109', '105', '123', '106', '125', '124', '114')

If I change the mappings @JoinColumn to read

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

I get the following error when loading my app:

org.hibernate.MappingException: Unable to find column with logical name: id in org.hibernate.mapping.Table(Category) and its related supertables and secondary tables

For good measure I also tried:

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

That gave me the error:

org.hibernate.MappingException: Unable to find column with logical name: TranslatableDescriptionId in org.hibernate.mapping.Table(Category) and its related supertables and secondary tables

Any suggestions to what I should do? I really want Category's translateableText to contain all the translations for its description, so I really want to join Category.TranslatableDescriptionId==TranslatableText.id

UPDATE1:
TranslatableText is used by many entities, so putting in a categoryId in it and reversing the relationship is not an option.

UPDATE2:
I was able to load it saying @JoinColumn(name="id"), but this led to a ClassCastException in Hibernate where it, instead of having an Integer as a key, has an Array containing a single Integer as a key. This fails to be made into a String and thus proper SQL. So it's probably still not the mapping I want

Cheers

Nik

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

山色无中 2024-10-01 00:29:37

这种映射是可能的,但不是很方便,因为您必须手动管理 TranslatableText 的标识(这就是 Hibernate 抱怨非映射列 TranslatableDescriptionId 的原因):

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

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

因此,您需要手动将唯一的 translatableDescriptionId 分配给 TranslatableText 的所有“目标”(如您所说的类别、项目、文件夹),并手动将此值设置为 在持久化之前,先检查 TranslatableText 的 id(您不能只将 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)); 

This kind of mapping is possible, but not very convenient because you'll have to manage identity of TranslatableTexts manually (that's why Hibernate complains about non-mapped column TranslatableDescriptionId):

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

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

So, you need to manually assign unique translatableDescriptionIds to all "targets" of TranslatableText (categories, items, folders as you say) and manually set this values as id of TranslatableText before persisting it (you can't just add TranslatableText into the Set).

--

However, the more convenient design is to introduce an intermediate entity to keep the identity of all transalations attatched to a specific target:

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)); 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文