Werfen Sie einen Blick auf meine Bücherliste unter it-rezension.de. Vielleicht sind Ihnen die Schaltflächen für die unterschiedlichen Sprachen aufgefallen? Die meisten Bücher sind mit deutschen Texten beschrieben, aber es gibt auch englische.

Die Geschäftsregel lautet: Zeige Texte in der gewählten Sprache. Falls nicht vorhanden, nutze Deutsch.

Das Buch-Objekt selbst ist eine einfache JPA-Entität:

package de.muellerbruehl.books.entities;

import de.muellerbruehl.books.enums.Language;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;

/**
  * This entity provides information about books like title,
  * publisher and especial information about its review.
  * @author mmueller
  */
@Entity
@Table(name = "Book")
public class Book implements Serializable {

       private static final long serialVersionUID = 1L;
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       @Column(name = "bookId")
       private Integer _id;
       @Column(name = "bookTitle")
       private String _title;
       @Column(name = "bookSubtitle")
       private String _subTitle;
       @Column(name = "bookAuthor")
       private String _author;
       @Column(name = "bookPublisher")
       private String _publisher;
       @Column(name = "bookYear")
       private Integer _year;
       @Column(name = "bookLanguage")
       @Enumerated(EnumType.STRING)
       private Language _language;
       @Column(name = "bookISBN")
       private String _isbn;
       @Column(name = "bookShorttext")
       private String _shorttext;
       @Column(name = "bookReference")
       private String _reference;
       @Column(name = "bookAdReference")
       private String _adReference;
       @OneToMany
       @JoinTable(name="mapBookCategory",
                       joinColumns=@JoinColumn(name="bcBookId"),
                       inverseJoinColumns=@JoinColumn(name="bcCategoryId"))
       private List<Category> _categories;
       @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
       @JoinColumn(name = "BookId", referencedColumnName="bookId")
       private List<ReviewLink> _reviewLinks;
// getters/setters omited for brevity

Ein Buch wird in der Tabelle “Book” gespeichert und die meisten Attribute auf die entsprechenden Spalten gemapt. Ein Buch mag in Kategoriern eingeordnet sein und über Links zu Rezensionen verfügen. Hierzu dienen die zwei Listen.

In der Datenbank gibt es eine weitere Tabelle mit den Ãœbersetzungen. Diese enthält folgende Attribute:

btId, btBookId, btLanguage, btShorttext, btReference, btAdReference

Das Prefix bt steht für “book translation”. BtId ist ein automatisch generierter Schlüssel ohne weitere Bedeutung. BookId refereniert ein Buch, während Language die Zielsprache definiert. Um einen Text in der Zielsprache zu erhalten, ist ein left join von Book zu BookTrans erforderlich, beispielsweise

select isnull(btShortText, bookShortText) as ShortText
from Book
join BookTrans on bookId=btBookId
where bookId=123 and btLanguage='en'

Dieses Statement selektiert das Buch mit der Id 123 sowie die Ãœbersetung, falls vorhanden. “isnull” ist die T-SQL Funktion um einen Null-Wert durch einen Default zu ersetzen.

Es ist also nicht mit einer einfachen JPA-Abfrage getan. Es gibt sicherlich unterschiedliche Lösungsmöglichkeiten; ich wollte JPA native query testen. Wichtig ist, das Ergebnis der Abfrage einer Java-Klasse zuzuweisen. Und da von der Struktur identisch, konnte ich hier direkt die Buch-Klasse nutzen:

public List<Book> getBooksByCategory(int catId, String languageCode) {
       String sqlQuery = "select bookId, bookTitle, bookSubtitle, bookAuthor, "
                       + "bookPublisher, bookYear, bookLanguage, bookISBN, "
                       + "isnull (btShortText, bookShorttext) as bookShorttext, "
                       + "isnull(btReference, bookReference) as bookReference, bookAdReference"
                       + " from book left join BookTrans on bookId = btBookId and btLanguage = ?1 "
                       + "join mapBookCategory on bookId = bcBookId and bcCategoryId = ?2 order by bookId desc;";
       return getEntityManager().createNativeQuery(sqlQuery, Book.class).
                       setParameter(1, languageCode).setParameter(2, catId).getResultList();
}