Is there a elegant and common way for converting P

2020-07-06 08:20发布

问题:

I have used JPA 2.1 Converter to convert PostgreSQL hstore to Map<String, String>. But I didn't find a universal way for different JPA providers such as EclipseLink and Hibernate. So I need to write different Converters for each JPA provider.

The following is the example which uses different Converters for EclipseLink and Hibernate. https://github.com/phstudy/jpa-converter-sample

Is there an universal way for different JPA providers?

回答1:

The PostgreSQL JDBC driver provides a org.postgresql.util.HStoreConverter utility class with to/from String and byte[] conversion. You can use it to implement your own JPA 2.1 Converter:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.util.Map;
import org.postgresql.util.HStoreConverter;

@Converter
public class MyHStoreConverter implements AttributeConverter<Map<String, String>, String> {
    @Override
    public String convertToDatabaseColumn(Map<String, String> attribute) {
        return HStoreConverter.toString(attribute);
    }

    @Override
    public Map<String, String> convertToEntityAttribute(String dbData) {
        return HStoreConverter.fromString(dbData);
    }
}

Then, use it with the JPA Convert annotation in your entity:

@Entity
public class MyEntity {
    @Convert(converter = MyHStoreConverter.class)
    private Map<String, String> hstoreAttribute;
}

This is an implementation using only JPA standards, so should be JPA-provider agnostic. However, using the Converter to map to a generic Map<> has earlier been blocked by the Hibernate bug HHH-8804, but that has been fixed in Hibernate 5.0.0 and 4.3.11.



回答2:

I haven't used it, but my understanding is that the new JPA 2.1 @Converter has been designed to bring a universal way to create a custom types.

It looks like you have the right solution but you're having troubles with the EclipseLink and Hibernate implementations.

You probably can find your way out by handling all different cases in a single convertToEntityAttribute(Object object) method.



回答3:

I have tried (parts of) your code, but get an exception when the table is generated: Internal Exception: org.postgresql.util.PSQLException: Error: Type »hstore« does not exist (Postgresql 9.1). This means I have only an idea. Try to define both methods:

@Override
convertToEntityAttribute(Object object)

and

//without @Override
convertToEntityAttribute(String string)

and then do the same for the other method. Eventually change which one is overriden.

PS: you could use the @ElementCollection annotation to directly map the Map, this way avoiding the Converters (if you are not working with a legacy DB that already has the data)