web-dev-qa-db-fra.com

Comment résoudre la colonne JSON en H2

J'utilise dans l'application MySQL 5.7 et j'ai des colonnes JSON. Lorsque j'essaie d'exécuter mes tests d'intégration, les tests ne fonctionnent pas car la base de données H2 ne peut créer la table. C'est l'erreur:

2016-09-21 16:35:29.729 ERROR 10981 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000389: Unsuccessful: create table payment_transaction (id bigint generated by default as identity, creation_date timestamp not null, payload json, period integer, public_id varchar(255) not null, state varchar(255) not null, subscription_id_zuora varchar(255), type varchar(255) not null, user_id bigint not null, primary key (id))
2016-09-21 16:35:29.730 ERROR 10981 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : Unknown data type: "JSON"; SQL statement:

C'est la classe d'entité.

@Table(name = "payment_transaction")
public class PaymentTransaction extends DomainObject implements Serializable {

    @Convert(converter = JpaPayloadConverter.class)
    @Column(name = "payload", insertable = true, updatable = true, nullable = true, columnDefinition = "json")
    private Payload payload;

    public Payload getPayload() {
        return payload;
    }

    public void setPayload(Payload payload) {
        this.payload = payload;
    }
}

Et la sous-classe:

public class Payload implements Serializable {

    private Long userId;
    private SubscriptionType type;
    private String paymentId;
    private List<String> ratePlanId;
    private Integer period;

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public SubscriptionType getType() {
        return type;
    }

    public void setType(SubscriptionType type) {
        this.type = type;
    }

    public String getPaymentId() {
        return paymentId;
    }

    public void setPaymentId(String paymentId) {
        this.paymentId = paymentId;
    }

    public List<String> getRatePlanId() {
        return ratePlanId;
    }

    public void setRatePlanId(List<String> ratePlanId) {
        this.ratePlanId = ratePlanId;
    }

    public Integer getPeriod() {
        return period;
    }

    public void setPeriod(Integer period) {
        this.period = period;
    }

}

Et ce convertisseur pour l'insertion dans la base de données:

public class JpaPayloadConverter implements AttributeConverter<Payload, String> {

    // ObjectMapper is thread safe
    private final static ObjectMapper objectMapper = new ObjectMapper();

    private Logger log = LoggerFactory.getLogger(getClass());

    @Override
    public String convertToDatabaseColumn(Payload attribute) {
        String jsonString = "";
        try {
            log.debug("Start convertToDatabaseColumn");

            // convert list of POJO to json
            jsonString = objectMapper.writeValueAsString(attribute);
            log.debug("convertToDatabaseColumn" + jsonString);

        } catch (JsonProcessingException ex) {
            log.error(ex.getMessage());
        }
        return jsonString;
    }

    @Override
    public Payload convertToEntityAttribute(String dbData) {

        Payload payload = new Payload();
        try {
            log.debug("Start convertToEntityAttribute");

            // convert json to list of POJO
            payload = objectMapper.readValue(dbData, Payload.class);
            log.debug("JsonDocumentsConverter.convertToDatabaseColumn" + payload);

        } catch (IOException ex) {
            log.error(ex.getMessage());
        }
        return payload;

    }
}
14
earandes

H2 n'a pas de type de données JSON.

JSON est essentiellement juste une chaîne potentiellement très longue, vous pouvez donc utiliser CLOB qui est disponible sur la plupart des bases de données.

Vous avez besoin d'un type JSON au niveau de la ligne uniquement si vous avez besoin d'une fonction SQL qui les exploite, et uniquement si la base de données insiste sur le fait que ses fonctions JSON fonctionnent sur un type JSON plutôt que sur un CLOB.

7
toolforger

Je viens de rencontrer ce problème en travaillant avec le type de colonne JSONB - la version binaire du type JSON, qui ne correspond pas à TEXT.

Pour référence future, vous pouvez définir un type personnalisé dans H2 à l'aide de CREATE DOMAIN, comme suit:

CREATE domain IF NOT EXISTS jsonb AS other;

Cela a semblé fonctionner pour moi, et m'a permis de tester avec succès mon code contre l'entité.

Source: https://objectpartners.com/2015/05/26/grails-postgresql-9-4-and-jsonb/

12
n00dle

J'ai résolu le problème en utilisant le type TEXT dans H2 . Il faut créer un script de base de données distinct pour créer le schéma dans H2 pour les tests et remplacer le type JSON par TEXT.

C'est toujours un problème car si vous utilisez la fonction Json dans les requêtes, vous ne pourrez pas les tester avec H2.

2
Olivier Garand

H2 n'a pas le type de données JSON.

Dans MySQL, le type JSON est simplement un alias du type de données LONGTEXT. Le type de données réel de la colonne est donc LONGTEXT.

0
Alex