将多语言数据库设计转换为JPA实体 [英] Convert multilanguage database design into JPA entities

查看:88
本文介绍了将多语言数据库设计转换为JPA实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在设计一个使用Java的多语言系统,在寻找最佳的数据库模型来存储多本地化文本的研究过程中,我走遍了Vertabelo的博客和一个很棒的设计,数据库模型

但是,由于该项目中有许多对象要本地化,因此我避免写所有Dao自己的文章,并尽可能使用JPA.

问题是我对JPA的了解还不多,所以我在Google上搜索了此问题的可用解决方案,并找到了另一篇很棒的博客文章(幸运的是,此处解决了Vertabelo博客中显示的相同设计: https://thoughts-on-java.org/localized-data-hibernate/)

    @Entity
    @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
    public class LocalizedProduct {

        @EmbeddedId
        private LocalizedId localizedId;

        @ManyToOne
        @MapsId("id")
        @JoinColumn(name = "id")
        private Product product;

        private String name;

        private String description;

        ...

}



@Embeddable
public class LocalizedId implements Serializable {

    private static final long serialVersionUID = 1089196571270403924L;

    private Long id;

    private String locale;

    public LocalizedId() {
    }

    public LocalizedId(String locale) {
        this.locale = locale;
    }

    // getter and setter methods ...
{

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @Version
    private int version;

    @ManyToOne(fetch = FetchType.LAZY)
    private Supplier supplier;

    private Double price;

    @OneToMany(mappedBy = "product", cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, orphanRemoval = true)
    @MapKey(name = "localizedId.locale")
    @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
    private Map<String, LocalizedProduct> localizations = new HashMap<>();

    ...

    public String getName(String locale) {
        return localizations.get(locale).getName();
    }

    public String getDescription(String locale) {
        return localizations.get(locale).getDescription();
    }
}

Product p = new Product();
p.setPrice(19.99D);

LocalizedProduct lpDe = new LocalizedProduct();
lpDe.setId(new LocalizedId("de"));
lpDe.setProduct(p);
lpDe.setName("Hibernate Tips - Mehr als 70 Lösungen für typische Hibernateprobleme");
p.getLocalizations().put("de", lpDe);

LocalizedProduct lpEn = new LocalizedProduct();
lpEn.setId(new LocalizedId("en"));
lpEn.setProduct(p);
lpEn.setName("Hibernate Tips - More than 70 solution to common Hibernate problems");
p.getLocalizations().put("en", lpEn);

em.persist(p);

然后是我想解决的问题.

"thoughts-on java"中提供的解决方案检索一个对象,该对象持有一个地图,其中包含来自所有语言的所有翻译,并且这种行为是不希望的,因为我的系统将以至少104种语言显示数据,最终.

问题是:是否有一种方法可以调整此解决方案,以便能够查询通过Entity ID和Locale ID的对象,并一次将翻译后的对象转换为一种语言?

解决方案

对于可能的变体,以下内容最简单/简洁:

class Product {
    long id;

    InternationalText name;
    InternationalText description;
}

class InternationalText {
    long id;
}

class LocalizedText {
    long id;

    InternationalText international;
    Locale locale;
    String text;
}

由于实际上并不需要InternationalText,因此它不需要List<LocalizedText> ONE_TO_MANY字段.加载product.name时,您不想加载所有语言.

我将细节留给您,因为您应该在单独的原型中进行尝试;处理所有细节;怎么做.调试确实确实延迟加载了东西.

I am designing a multilanguage system using Java, and during my research to find the best database model to store multi-localized text, I came accross Vertabelo's blog and this wonderful design, from here:

Database model

However, as there are lots of objects to be localized in the project, I am avoiding to write all the Dao's myself, and stick with JPA, if possible.

The thing is that I don't know much of JPA yet, so I googled for available solutions to this problem, and found another great blog post (which fortunatelly addresses the same design shown in Vertabelo's blog here: https://thoughts-on-java.org/localized-data-hibernate/)

    @Entity
    @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
    public class LocalizedProduct {

        @EmbeddedId
        private LocalizedId localizedId;

        @ManyToOne
        @MapsId("id")
        @JoinColumn(name = "id")
        private Product product;

        private String name;

        private String description;

        ...

}



@Embeddable
public class LocalizedId implements Serializable {

    private static final long serialVersionUID = 1089196571270403924L;

    private Long id;

    private String locale;

    public LocalizedId() {
    }

    public LocalizedId(String locale) {
        this.locale = locale;
    }

    // getter and setter methods ...
{

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @Version
    private int version;

    @ManyToOne(fetch = FetchType.LAZY)
    private Supplier supplier;

    private Double price;

    @OneToMany(mappedBy = "product", cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, orphanRemoval = true)
    @MapKey(name = "localizedId.locale")
    @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
    private Map<String, LocalizedProduct> localizations = new HashMap<>();

    ...

    public String getName(String locale) {
        return localizations.get(locale).getName();
    }

    public String getDescription(String locale) {
        return localizations.get(locale).getDescription();
    }
}

Product p = new Product();
p.setPrice(19.99D);

LocalizedProduct lpDe = new LocalizedProduct();
lpDe.setId(new LocalizedId("de"));
lpDe.setProduct(p);
lpDe.setName("Hibernate Tips - Mehr als 70 Lösungen für typische Hibernateprobleme");
p.getLocalizations().put("de", lpDe);

LocalizedProduct lpEn = new LocalizedProduct();
lpEn.setId(new LocalizedId("en"));
lpEn.setProduct(p);
lpEn.setName("Hibernate Tips - More than 70 solution to common Hibernate problems");
p.getLocalizations().put("en", lpEn);

em.persist(p);

Then comes the problem I wanna solve.

The solution presented in "thoughts-on java" retrieves an object holding a map with all translations from all languages attached in it, and this behavior is not desired, as my system is going to present data in at least 104 languages, eventually.

The question is: is there a way to tune this solution in order to be able to query for an object passing Entity id and Locale id and get a translated object to a single language at a time?

解决方案

For the possible variants, the following is simplest/concize:

class Product {
    long id;

    InternationalText name;
    InternationalText description;
}

class InternationalText {
    long id;
}

class LocalizedText {
    long id;

    InternationalText international;
    Locale locale;
    String text;
}

As the InternationalText is not really needed, it does not need a List<LocalizedText> ONE_TO_MANY field. On loading a product.name you do not want to load all languages.

I leave the details to you, as you should in a separate prototype try it out; work all details; how to do things. Debugging that things indeed are lazily loaded etcetera.

这篇关于将多语言数据库设计转换为JPA实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆