【问题标题】:Map complex value objects in Hibernate在 Hibernate 中映射复杂的值对象
【发布时间】:2017-03-11 15:56:06
【问题描述】:

我已经在Hibernate's forum 上问过这个问题,但我想我也会在这里问。

我正在尝试映射以下模型,同时保留 TranslatedTextTranslation 值对象的值语义:

作为依赖对象的两个值

理想情况下,我会将TranslatedText 映射为Question 内的<component>,并将Translation 映射为<composite-element> 内的<bag> TranslatedText

如果Question 只引用一个TranslatedText,映射会很简单,但由于它引用了两个,我需要某种基于持有值的属性名称的鉴别器(title 或@987654338 @) 以便将Translation 映射到由(question_id,property_name,language_code) 组成的外键。

其中一个问题是 propertyName 不是模型的一部分,也不应该,但我还没有找到一种方法来强制 Hibernate 插入一个不是来自模型的值。

因此,我尝试更改模型并引入专门的 TitleDescription 类,以便在其中有一个 type 可以用作鉴别器。

最后并没有太大帮助:

  <component name="title" class="TranslatedText">

     <bag name="translations" table="Translation">
        <key>
           <!-- PROBLEM: Could not find a way to create a custom join expression on question.id and question.title.type in here. -->
        </key>

        <composite-element class="Translation">
           <!-- PROBLEM: Could not found a way to make Hibernate insert title.type from here, without having this value on the Translation object. -->
           <property name="languageCode" type="string" column="language_code"/>
           <property name="text" type="string"/>
        </composite-element>
     </bag>
  </component>

带有&lt;many-to-one&gt;的翻译文本

通过使用&lt;many-to-one&gt;TranslatedText 映射为Question 中的实体,然后将Translation 映射为TranslatedText 中的值集合,我设法得到了接近我需要的东西,但主要问题采用这种方法是没有简单的方法可以摆脱孤立的TranslatedTextTranslation。我要么必须使用数据库触发器或计划进程来执行此操作。

结论

在这一点上,我的印象是 Hibernate 不够灵活,无法使用正确的语义映射初始模型,但希望我错了,有办法做到这一点。

【问题讨论】:

    标签: java hibernate domain-driven-design hibernate-xml-mapping


    【解决方案1】:

    我还没有找到将它们映射为值的方法。但是,下一个解决方案有效,它可能对您有所帮助。我删除了TranslatedText 并将QuestionTranslation 的集合直接关联。

    @Entity
    public class Question {
        @Id
        private String id;
    
        @JoinTable
        @OrderColumn
        @OneToMany(fetch = EAGER, cascade = ALL)
        private List<Translation> titleTranslations;
    
        @JoinTable
        @OrderColumn
        @OneToMany(fetch = EAGER, cascade = ALL)
        private List<Translation>  descriptionTranslations;
    }
    

    这里的缺点是Translation 必须是Entity 类。

    @Entity
    public class Translation {
        @Id
        private String id;
        private String languageCode;
        private String text;
    }
    

    【讨论】:

    • 好吧,TranslatedText 很有用,因为它确保每个代码只有一次翻译,所以我不能只是摆脱它,除非我使用数据库约束强制执行规则,但模型不会表现力。如果它是在 java 中,我可以使用 Set&lt;Translation&gt;,但我们不能这样做,因为模型实际上是用 ColdFusion(是的,那种可怕的语言)而不是 java 编写的。
    • 在没有上下文的情况下很难理解您的约束,但是可以通过将所有三个类都设为@Entity 来建立这种关系(每个类都有自己的@Id)。你可以吗?如果是这样,我可以准备这样的配置。
    • 好吧,就像我说的,我已经通过将TranslatedText 映射为一个实体来做到这一点。但是,在这种情况下我不能做cascade-delete-orphan,因为我使用了many-to-one。值对象只是简单的不可变值,例如 DateInteger。将它们映射为休眠组件将解决孤儿问题。我真的很惊讶这种常见的场景是如此难以映射。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 2018-10-27
    相关资源
    最近更新 更多