1

I've already asked this question on the Hibernate's forum, but I thought I'd ask it here too.

I'm trying to map the following model while preserving the value semantics of the TranslatedText and Translation value objects:

enter image description here

Both values as dependent objects

Ideally I'd map TranslatedText as a <component> within Question and Translation as a <bag> of <composite-element> within TranslatedText.

It would have been simple to map if Question was only referencing one TranslatedText, but since it references two I need some kind of discriminator based on the name of the property holding the value (title or description) in order to map the Translation with a foreing key composed of (question_id,property_name,language_code).

One problem with that is that the propertyName isin't part of the model and shouldn't, but I haven't found a way to force Hibernate to insert a value that doesn't come from the model.

Therefore, I tried to change the model and introduce specialized Title and Description classes so that I'd have a type in there that I could use as a discriminator.

enter image description here

At the end that did not really help much:

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

TranslatedText with <many-to-one>

I managed to get something close to what I need by mapping TranslatedText as an entity within Question using a <many-to-one> and then map Translation as a collection of values within TranslatedText, but the main problem with that approach is that there is no easy way to get rid of the orphaned TranslatedText and Translation. I'd either have to do this with a DB trigger or a scheduled process.

Conclusion

At this point I'm under the impression that Hibernate is not flexible enough to map the initial model with the proper semantics, but hopefully I'm wrong and there is a way to do it.

Neil Stockton
  • 11,383
  • 3
  • 34
  • 29
plalx
  • 42,889
  • 6
  • 74
  • 90

1 Answers1

1

I have not found a way to map them as values. However the next solution works and it might be helpful for you. I removed TranslatedText and linked Question directly with collection of Translation.

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

The drawback here is that Translation has to be Entity class.

@Entity
public class Translation {
    @Id
    private String id;
    private String languageCode;
    private String text;
}
Sasha Shpota
  • 9,436
  • 14
  • 75
  • 148
  • Well, `TranslatedText` is useful as it ensures only one translation per code so I can't just get rid of it, unless I enforce the rule with a DB constraint, but the model wouldn't be as expressive. I could use `Set` instead if it was in java, but we can't do it since the model is actually written in ColdFusion (yes that horrible language), not java. – plalx Mar 11 '17 at 19:14
  • It is hard to understand your constraints without context but It is possible to have such relation by making all three classes as `@Entity` (each of them will have its own `@Id`). Is it ok for you? If so I can prepare such configuration. – Sasha Shpota Mar 11 '17 at 19:22
  • Well, like I said I managed to do it already by mapping `TranslatedText` as an entity. However, I can't do `cascade-delete-orphan` in that case since I've used a `many-to-one`. Value objects are just simple immutable values like `Date` or `Integer`. Mapping them as hibernate components would fix the orphan problem. I'm actually surprised such common scenario is so hard to map. – plalx Mar 11 '17 at 22:14