JPA映射一个Embeddable类,其中包含Map <entity,embeddable =“”> </entity,>

时间:2014-06-06 15:35:19

标签: java java-ee jpa orm eclipselink

我正在使用JPA编写Java EE应用程序,它需要国际化。 为此,我创建了一个名为MultilingualString的课程,该课程将LanguageString相关联 (以及如此扩展HashMap<Language, String>)如下:

/**
 * This class is mapped to the database thanks
 * to the Locale.toLanguageTag() method
 * and Locale.fromLanguageTag(String) constructor
 */
public class Language {
    public Locale locale;

    /* Getters, Setters ... */  
}

/**
 * NB : This class extends HashMap to override the put method
 * which needs to ignore putting null values instead of throwing
 * a NullPointerException
 */
public class MultilingualString extends HashMap<Language, String> {
    public Map<Language, String> getStrings() {
        return (this);
    }

    /* ... */
}

现在,我们假设Entity的名称不同,具体取决于Language

@Entity
@Access(AccessType.PROPERTY)
public class Entity {
    private Long id;
    private MultilingualString name;

    @Id
    public Long getId() { ... }

    @Transient
    public MultilingualString getName() { ... }

    @ElementCollection
    @MapKeyJoinColumn(name = "language_id")
    public Map<Language, String> getStrings() {
        return (this.name.getStrings());
    }

    /* ... */
}

此代码生成以下数据库架构:

Language        :
    id          | bigint                        | NOT NULL  | primary key
    languageTag | character varying(255)        |           |
---------------------------------------------------------------------------------------------------
Entity          :
    id          | bigint                        | NOT NULL  | primary key
---------------------------------------------------------------------------------------------------
Entity_strings  :
    entity_id   | bigint                        |           | foreign key references Entity(id)
    language_id | bigint                        |           | foreign key references Language(id)
    string      | character varying(255)        |           |

这几乎是好的。

此实现的问题是重复@Transient字段上的MultilingualString@ElementCollection @MapKeyJoinColumn方法上的getStrings()(每次都必须重写) 您需要在数据库BTW中映射​​MultilingualString:每个实体类至少1个)。 在我看来,它使代码变得难看并且难以维护。

另一件事是:EntityLanguageStringMap相关联。 应该有一个关联它们的课程:在我读的时候说LocalizedString here

所以我希望MultilingualString的行为类似于值类型 我不需要重复上面提到的那些多个注释并实现LocalizedString

以下是我到目前为止所提出的内容。它不起作用,GlassFish不会开始 使用这样的映射,当EclipseLink看到java.util.NoSuchElementException映射时,我总是得到MultilingualString

@Embeddable
public class LocalizedString {
    @ManyToOne
    private Language language;
    private String string;
}

@Embeddable
public class MultilingualString extends HashMap<Language, LocalizedString> {

    /**
     * Here I lost myself in all the available annotations
     * and tried thousands of permutation, but always the same exception
     * @MapKeyJoinColumn ?
     * @MapKeyClass ?
     * @CollectionTable ?
     * ...
     */
    @ElementCollection
    public Map<Language, LocalizedString> getStrings() {
        return (this);
    }
}

@Entity
public class Entity {
    @Id
    private Long id;
    @Embedded
    private MultilingualString name;
}

因此,我希望通过此实现获得与上面所述相同(或最接近的)数据库映射。 这甚至可能吗?我读到Embeddable类不应该包含另一个({1}}类的集合,但在这里,对我来说就是这种情况。

我阅读了几篇文章和博客,并没有发现像这样的很多情况(&#34; JPA Map with Entity key and Embeddable value&#34;)

实际上,我尝试做类似this的事情 除了我的地图值是Embeddable类。 我找到了ONE similar situation (除了我希望他的Embeddable类是Root)在StackOverflow上,我测试了一个答案(没有运气),但它没有被标记为答案&#34;这个问题没有取得多大成功。

1 个答案:

答案 0 :(得分:0)

以下是可以处理实体本地化的方面示例:

@Aspect
public class LocalizationAspect {

    @AfterReturning(
            pointcut = "@within(MyManager) && execution(MyEntity methodThatReturnsEntity(..))",
            returning = "entity"
    )
    public void localizeMyEntity(MyEntity entity) {
        localize(entity);
    }
}

通过微小的更改,您可以将其应用于返回实体的集合......

localie()在返回结果之前使用实体ID导航并将本地化信息注入该实体。