是否可以不使用@Embeddable将JPA/Hibernate实体字段Map到另一个类中的字段?

im9ewurl  于 2022-11-14  发布在  其他
关注(0)|答案(2)|浏览(190)

我有一个非常简单的实体(Person.java),我希望通过JPA/Hibernate持久化该实体。ID和标识字符串。
ID是一个简单的Integer,没有问题。Identification String当前是一个String,但由于各种原因,我想使用String的 Package 类(IDString),其中有各种验证方法。
我想知道如何让JPA/Hibernate使用 Package 的字符串(在自定义类IDString中)。我知道这可能可以通过让IDString为@Embeddable然后用@Embedded将IDString嵌入到Person实体中来解决,但我正在寻找另一种方法,主要是因为IDString在一个完全不同的包中,我不愿意去那里改变东西。
谷歌搜索,我发现https://www.baeldung.com/hibernate-custom-types,但它似乎主要是关于更复杂的情况下,你想把一个类转换成另一个类型,我确实觉得可能有一个更聪明的方法,我只是忽略了。
这里是实体(在理论上)

@Entity(name="Person")
@Table(name="DB_TABLE_PERSON")
public class Person implements Serializable {
    @Id
    Integer id;
    // WHAT SHOULD I PUT HERE? I WANT TO SIMPLY USE THE STRING INSIDE IDSTRING AS THE FIELD TO PERSIST
    IDString idString;

    // getter and setter for ID.
    
    public void getIdString() {
        return idString.getValue();
    }
    public void setIdString(String in) {
        idString.setValue(in);
    }
}

下面是IDString类(理论上):

public class IDString {
    // I really want to be a POJO
    private final String the_string;
    public IdString(String input) {
        if (isValid(input)) {
            the_string = input;
        } else {
            throw new SomeCoolException("Invalid format of the ID String");
        }
    public boolean isValid(String input) {
        // bunch of code to validate the input string
    }
    public String getValue() {
        return the_string;
    }
    public void setValue(String input) {
        if (isValid(input)) the_string = s;
        else throw new SomeCoolException("Invalid format of the ID String");
}

我知道如果IDString在Entity里面我可以放置验证,但是IDString将在其他地方使用(它是一个通用的自定义类),所以我不想这样做。有简单的方法吗?

up9lanfz

up9lanfz1#

@Converter(autoApply=true) // autoApply is reasonable, if not use @Converter on field
public class IDStringConverter implements AttributeConverter<IDString,String> {
  @Override
  public String convertToDatabaseColumn(IDString attribute) {
    return attribute != null ? attribute.getValue() : null;
  }

  @Override
  public IDString convertToEntityAttribute(String dbData) {
    return dbData != null ? new IDString(dbData) : null;
  }
}

这样就不需要在代码中做任何修改了。AttributeConverter的一个限制是它只能从一个Java字段Map到一个DB列。如果你想Map到更多的列(这里不是这样),你需要嵌入对象。

rdrgkggo

rdrgkggo2#

您还可以在getter上放置@Column注解:

@Entity
public class Person {

    private final IdString idString = new IdString();

    @Column(name = "ID_STRiNG")      
    public IdString getIdString() {
        return idString.getValue();
    }

    public void setIdString(String input) {
        idString.setValue(input);
    }

另一个解决方案是使用@PostLoad和@PrePersit事件处理函数在IdString之间进行转换:

@Entity
public class Person {

    @Column(name = "ID_STRiNG")
    private String the_string; // no getters & setters

    @Transient
    private final IdString idString = new IdString();

    @PostLoad
    public void postLoad() {
        idString.setValue(the_string);
    }

    @PrePersist
    public void prePersist() {
        the_string = idString.getValue();
    }

    // getters & setters for idString

相关问题