【问题标题】:Hibernate: joining with one of the keys of a multi-keyed tableHibernate:与多键表的键之一连接
【发布时间】:2010-09-17 07:56:15
【问题描述】:

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

在我的 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 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 ('1 ','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:无法在 org.hibernate.mapping.Table(Category) 及其相关的超级表和辅助表中找到具有逻辑名称的列:TranslatableDescriptionId

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

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

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

干杯

尼克

【问题讨论】:

    标签: java hibernate orm hibernate-onetomany


    【解决方案1】:

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

    public class Category implements Serializable {
        ...
        private Long translatableDescriptionId;
    
        @OneToMany
        @JoinColumn(name="id", referencedColumnName="TranslatableDescriptionId") 
        private Set<TranslatableText> translatableText;
        ...
    }
    

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

    【讨论】:

    • 感谢您的建议,我将立即尝试该设计并报告:-) 我有点困惑,但是,由于我阅读它的方式,我只是在推动问题走到我面前?
    • 'name = "targetId"' in Category 指向 Category.targetId,对吧?还是应该是 'name = "id"' 因为它指向 TranslationTargets.id,就像 TranslationTarget 的 'name = "targetId"' 指向 TranslatableText.targetId?
    • 执行此操作时,出现以下异常。我错过的映射中有什么东西吗? com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:“字段列表”中的未知列“texts0_.targetId”
    • @niklassaers: name in @ManyToOne's @JoinColumn 指向“多”端的外键名称(即TranslatableText.targetId),然后在@OneToOne 中指向到当前侧,即Category.targetId.
    • @niklassaers:请注意,我将TranslatableTextid 重命名为targetId
    猜你喜欢
    • 2016-04-27
    • 1970-01-01
    • 1970-01-01
    • 2013-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多