JPA枚举类型映射。最佳方法 [英] JPA enumerated types mapping. Best approach

查看:1350
本文介绍了JPA枚举类型映射。最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

像普通的Java枚举类型有相应的代码和名称描述。
包含这些字段的Java类包含它们作为枚举:

  public enum MyEnum {
SOMEINSTANCE (1,test1),
SOMEINSTANCE(2,test2);

private final int code;
private final String name;
private MyEnum(int code,String name){
this.code = code;
this.name = name;
}
...代码和名称的助手getter
}

@Entity
puclic类EnumHolder {
private MyEnum myEnum;
}

我是JPA的新手,但我希望拥有' code> myEnums '表,看起来像:

 代码不为空,名称为varchar (50)not null)

在我的 enumHolder 表我想要有指向myEnums表的 myEnumCode 字段。



使用currenlty支持EnumType .ORDINAL和EnumType.STRING我想不是一个好主意。



另一个问题。如何使用Java MyEnum 类数据填充 myEnums 表?你会怎么做?最好的方法请。



PS:这里是我可以提供的解决方案:



假设有 myEnum 代码和名称字段。 Java MyEnum 枚举,这是在问题中描述的。 enumHolder 表需要有 myEnumCode 引用 myEnum.code 领域。如果您不同意,请评论该解决方案。

  @Entity 
@Access(AccessType.FIELD)
public EnumHolder类{
@Id private int id;
@Transient private MyEnum myEnum;
...
public int getId(){return id; }
public void setId(int id){this.id = id; }
public MyEnum getMyEnum(){return MyEnum; }
public void setMyEnum(MyEnum myEnum){this.myEnum = myEnum;

@Access(AccessType.PROPERTY)@Column(name =myEnumCode)
protected int getMyEnumForDb(){
return myEnum.getCode();
}

protected void setMyEnumForDb(int enumCode){
myEnum = MyEnum.getByCode(enumCode);
}
...
}

当然这里有缺点。但是目前我看不到更好的方法。 EnumType.ORDINAL和EnumType.STRING的替代方法请不要提供。我不想在这里写出所有可能存在的问题(在有效的Java中,它是关于序数使用的描述)。使用EnumType.STRING我不喜欢这样做,因为它不允许在数据库中有描述并从db请求它。



关于fillind数据库。我认为编写一个脚本并不难,它清除了 myEnum 表,然后每个Java枚举都将插入到表中。并且总是在部署阶段执行。

解决方案

最好的方法是将唯一的ID映射到每个枚举类型,从而避免ORDINAL和STRING的陷阱。请参阅帖子,其中概述了5种方式可以映射一个枚举。



从上面的链接获取:



1& 2。使用@Enumerated



目前有两种方法可以使用@Enumerated注释在JPA实体中映射枚举。不幸的是,EnumType.STRING和EnumType.ORDINAL都有其限制。



如果使用EnumType.String,那么重命名其中一个枚举类型会导致您的枚举值超出与保存在数据库中的值进行同步。如果您使用EnumType.ORDINAL,则删除或重新排序枚举中的类型将导致数据库中保存的值映射到错误的枚举类型。



这两个选项是脆弱的如果在不执行数据库迁移的情况下修改枚举,则可能会损害数据的完整性。



3。生命周期回调



可能的解决方案将使用JPA生命周期回调注释@PrePersist和@PostLoad。这感觉相当难看,因为您现在将在您的实体中有两个变量。一个映射存储在数据库中的值,另一个映射实际的枚举。



4。将唯一ID映射到每个枚举类型



首选解决方案是将枚举映射到在枚举中定义的固定值或ID。映射到预定义的固定值使您的代码更加强大。对枚举类型的顺序或名称重构的任何修改都不会造成任何不利影响。



5。使用Java EE7 @Convert



如果您使用JPA 2.1,您可以选择使用新的@Convert注释。这需要创建一个转换器类,用@Converter注释,其中您将为每个枚举类型定义保存到数据库中的值。在您的实体中,您将使用@Convert对您的枚举进行注释。



我的偏好:(第4号)



我更喜欢在枚举中将我的ID定义为反对使用转换器,是很好的封装。只有枚举类型应该知道其ID,只有实体应该知道如何将枚举映射到数据库。



查看原始的 post 代码示例。


As usual Java enum types have corresponding codes and name description. And Java classes that contain such fields, contain them as Enum:

public enum MyEnum{
    SOMEINSTANCE(1, "test1"),
    SOMEINSTANCE(2, "test2");

    private final int code;
    private final String name;
    private MyEnum(int code, String name){
        this.code = code;
        this.name = name;
    }
    ... helper getter for code and name
}

@Entity
puclic class EnumHolder{
    private MyEnum myEnum;
}

I'm a newbie to JPA, but I wish to have the 'myEnums' table, looked like:

code int not null, name varchar(50) not null)

And in my enumHolder table I want to have the myEnumCode field that points to the myEnums table.

Using currenlty supported both EnumType.ORDINAL and EnumType.STRING I suppose not a good idea.

And another question. How can I fill in the myEnums table using Java MyEnum class data? How would you do it? The best approach please.

PS: here are solutions I can offer:

Let's suppose there is table myEnum with code and name fields. Java MyEnum enum, that is described in the question. enumHolder table need to have myEnumCode reference to myEnum.code field. Please comment the solution if you disagree.

@Entity
@Access(AccessType.FIELD)
public class EnumHolder {
    @Id private int id;
    @Transient private MyEnum myEnum;
    …
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public MyEnum getMyEnum() { return MyEnum; }
    public void setMyEnum(MyEnum myEnum) { this.myEnum = myEnum; }

    @Access(AccessType.PROPERTY) @Column(name="myEnumCode")
    protected int getMyEnumForDb() {
        return myEnum.getCode();
    }

    protected void setMyEnumForDb(int enumCode) {
        myEnum = MyEnum.getByCode( enumCode);
    }
…
}

Of course there are drawbacks here. But at the moment I cannot see the better approach. Alternatives with EnumType.ORDINAL and EnumType.STRING please don't offer. I don't want to write here all problems that can exist with its usage (in Effective Java it is described concerning ordinals usage). Using EnumType.STRING I don't like either cause it does not allow to have discription in database and request it from db.

Concerning fillind database. I think it's not difficult to write a script, that clears the myEnum table and then for each Java enum istance makes insert into the table. And always do it during a deployment phase.

解决方案

The best approach would be to map a unique ID to each enum type, thus avoiding the pitfalls of ORDINAL and STRING. See this post which outlines 5 ways you can map an enum.

Taken from the link above:

1&2. Using @Enumerated

There are currently 2 ways you can map enums within your JPA entities using the @Enumerated annotation. Unfortunately both EnumType.STRING and EnumType.ORDINAL have their limitations.

If you use EnumType.String then renaming one of your enum types will cause your enum value to be out of sync with the values saved in the database. If you use EnumType.ORDINAL then deleting or reordering the types within your enum will cause the values saved in the database to map to the wrong enums types.

Both of these options are fragile. If the enum is modified without performing a database migration, you could jeopodise the integrity of your data.

3. Lifecycle Callbacks

A possible solution would to use the JPA lifecycle call back annotations, @PrePersist and @PostLoad. This feels quite ugly as you will now have two variables in your entity. One mapping the value stored in the database, and the other, the actual enum.

4. Mapping unique ID to each enum type

The preferred solution is to map your enum to a fixed value, or ID, defined within the enum. Mapping to predefined, fixed value makes your code more robust. Any modification to the order of the enums types, or the refactoring of the names, will not cause any adverse effects.

5. Using Java EE7 @Convert

If you are using JPA 2.1 you have the option to use the new @Convert annotation. This requires the creation of a converter class, annotated with @Converter, inside which you would define what values are saved into the database for each enum type. Within your entity you would then annotate your enum with @Convert.

My preference: (Number 4)

The reason why I prefer to define my ID's within the enum as oppose to using a converter, is good encapsulation. Only the enum type should know of its ID, and only the entity should know about how it maps the enum to the database.

See the original post for the code example.

这篇关于JPA枚举类型映射。最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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