1

Situation

I have two Hibernate entities, Document and TitleTranslation, with a one-to-many relationship, as there are multiple titles for a document, one for each language. Document has a property id and TitleTranslation references that through document_id.

Therefore, to connect titles to documents, the natural solution would be a field as follows:

@JoinColumn(name = "document_id")
List<TitleTranslation> translations;

Goal

For sorting, I'm currently passing a Sort object to a JPA repository, e.g. repository.findAll(mySort). The sort order property may reference transitive properties, such as owner.firstname (document has owner, owner has firstname).

This works well as long as transitive properties are joined in a one-to-one fashion, but breaks down for one-to-many relationships as above: I'd like to sort by a document's title, but there's just a list of translations. However, since I'm just interested in one specific language, there is just one title in the list relevant to me, therefore a de-facto one-to-one relationship.

How can I achieve a one-to-one mapping to a translation of a certain language, so I could sort by e.g. translationEn.title?

Partial solution

As it turns out, mapping through OneToOne results in one of the translations being picked (the first one?):

@OneToOne(mappedBy = "document")
TitleTranslation translation;

This relies on a corresponding mapping in TitleTranslation:

@JoinColumn(name = "document_id", referencedColumnName = "id")
Document document;

Now, I would like to indicate on the translation property that only translations with language='en' should be joined. I tried to use the Where annotation, but this only works in connection with one-to-many relationships. Thus, the following doesn't work as expected:

@OneToOne(mappedBy = "document")
@Where(clause = "language='en'")
TitleTranslation translation;
Cedric Reichenbach
  • 8,970
  • 6
  • 54
  • 89

1 Answers1

2

You could try using filters:

1) Define the filter:

@FilterDef(name = "enFilter"
                , defaultCondition=" language='en'")
public class TitleTranslation {

2) Use the filter:

@ManyToOne(mappedBy = "document")
@Filter(name = "enFilter")
TitleTranslation translation;

You may need to define a @ManyToOne instead of @OneToOne though.

3) In transactional method:

Session session = sessionFactory.getCurrentSession();
session.enableFilter("enFilter");
Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
  • Actually, I've tried something similar. The problem is that I'm using JPA and do the request in the fashion of `repository.findAll(sort)`, so I don't have a session reference. Or is there a way to always enable that filter by default? – Cedric Reichenbach Nov 21 '17 at 14:15
  • There is no straightforward way. This is bit of a workaround https://stackoverflow.com/questions/25855260/global-hibernate-filter-on-all-database-queries – Maciej Kowalski Nov 21 '17 at 14:33
  • Okay, I got it to work with JPA by getting the session first, from an injected `ObjectFactory` as follows: `emProvider.getObject().unwrap(Session.class)`. Maybe you can add this to the answer, then I'll accept it. For what it's worth, I'm now using multiple filters, one per language, and selectively activating them before a JPA call. – Cedric Reichenbach Nov 22 '17 at 10:19