Quarkus Hibernate:通过方法提供的更改值时实体未更新

Quarkus Hibernate: Entity not updated when changed value provided via method

我使用 Quarkus + Hibernate 将数据同步到数据库,我在测试期间注意到有时我的实体没有更新。我创建了一个调整原始示例的最小示例 https://github.com/quarkusio/quarkus-quickstarts/tree/main/hibernate-orm-quickstart

这是我的调整:

import.sql

DROP TABLE IF EXISTS fruit CASCADE;
CREATE TABLE fruit (
    fruitsSequence INT PRIMARY KEY,
    name TEXT NOT NULL,
    test INT
);

Fruit.java

package org.acme.hibernate.orm;

import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

import com.google.common.base.Objects;

@Entity
@Table(name = "known_fruits")
public class Fruit {

    @Id
    @SequenceGenerator(name = "fruitsSequence", sequenceName = "known_fruits_id_seq", allocationSize = 1, initialValue = 10)
    @GeneratedValue(generator = "fruitsSequence")
    private Integer id;

    @Transient
    private String name = "";

    @Column(name = "test")
    private Integer test = -1;

    public Fruit() {
    }

    public Fruit(String name) {
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name = "name")
    @Access(AccessType.PROPERTY)
    public String getChangedName() {
        return "a" + name;
    }

    public String getName() {
        return name;
    }

    public void setTest(Integer test) {
        this.test = test;
    }

    public Integer getTest() {
        return test;
    }

    @Column(name = "name")
    @Access(AccessType.PROPERTY)
    protected void setChangedName(String name) {
        this.name = name.substring(1);
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(name, test);
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Fruit) {
            Fruit other = (Fruit) o;
            return name.equals(other.name) && test.equals(other.test);
        }

        return false;
    }
}

将测试替换为DBTest.java

package org.acme.hibernate.orm;

import static io.restassured.RestAssured.given;
import static org.junit.jupiter.api.Assertions.assertEquals;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.UserTransaction;

import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class DBTest {

    @Inject
    EntityManager m_em;

    @Inject
    UserTransaction m_transaction;

    @Test
    void testUpdate() throws Exception {
        Fruit fruit = given().when().body("{\"name\" : \"Pear\"}").contentType("application/json").post("/fruits")
                .then().statusCode(201).extract().as(Fruit.class);

        m_transaction.begin();
        Fruit db = m_em.find(Fruit.class, fruit.getId());
        db.setName("Apple");
        db.setTest(13);
        m_transaction.commit();

        db = m_em.find(Fruit.class, fruit.getId());

        assertEquals(13, db.getTest(), "Unexpected test");
        assertEquals("Apple", db.getName(), "Unexpected name");
    }

    @Test
    void testUpdateLongName() throws Exception {
        Fruit fruit = given().when().body(
                "{\"name\" : \"PeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDBaaaaaaaaaaaaaar\"}")
                .contentType("application/json").post("/fruits").then().statusCode(201).extract().as(Fruit.class);

        m_transaction.begin();
        Fruit db = m_em.find(Fruit.class, fruit.getId());
        db.setName(fruit.getName() + "Apple");
        db.setTest(13);
        m_transaction.commit();

        db = m_em.find(Fruit.class, fruit.getId());

        assertEquals(13, db.getTest(), "Unexpected test");
        assertEquals(fruit.getName() + "Apple", db.getName(), "Unexpected name");
    }

    @Test
    void testUpdateNameOnly() throws Exception {
        Fruit fruit = given().when().body("{\"name\" : \"Pear\"}").contentType("application/json").post("/fruits")
                .then().statusCode(201).extract().as(Fruit.class);

        m_transaction.begin();
        Fruit db = m_em.find(Fruit.class, fruit.getId());
        db.setName("Apple");
        m_transaction.commit();

        db = m_em.find(Fruit.class, fruit.getId());

        assertEquals(-1, db.getTest(), "Unexpected test");
        assertEquals("Apple", db.getName(), "Unexpected name");
    }

    @Test
    void testUpdateNameOnlyREST() throws Exception {
        Fruit fruit = given().when().body("{\"name\" : \"Pear\"}").contentType("application/json").post("/fruits")
                .then().statusCode(201).extract().as(Fruit.class);

        given().when().body("{\"name\" : \"Apple\"}").contentType("application/json").put("/fruits/" + fruit.getId())
                .then().statusCode(200).extract().as(Fruit.class);

        Fruit db = m_em.find(Fruit.class, fruit.getId());

        assertEquals(-1, db.getTest(), "Unexpected test");
        assertEquals("Apple", db.getName(), "Unexpected name");
    }
}

我看到 testUpdateNameOnlytestUpdateNameOnlyREST 失败,而其他测试 运行 符合预期。在我原来的测试用例中,即使更改另一个字段也不会更新 TEXT 字段,因此测试名称很长。写入数据库时​​更改名称的原因是对其进行加密(结果是 BASE64 字符串)。 我不确定这是配置问题还是实际错误。

提前感谢您的帮助!

正如评论所暗示的那样,这似乎是一个错误 (https://github.com/quarkusio/quarkus/issues/16619)。 它适用于 AttributeConver:

Fruit.java:

package org.acme.hibernate.orm;

import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import com.google.common.base.Objects;

@Entity
@Table(name = "known_fruits")
public class Fruit {

    @Id
    @SequenceGenerator(name = "fruitsSequence", sequenceName = "known_fruits_id_seq", allocationSize = 1, initialValue = 10)
    @GeneratedValue(generator = "fruitsSequence")
    private Integer id;

    @Column(name = "name")
    @Convert(converter = NameConverter.class)
    private String name = "";

    @Column(name = "test")
    private Integer test = -1;

    public Fruit() {
    }

    public Fruit(String name) {
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setTest(Integer test) {
        this.test = test;
    }

    public Integer getTest() {
        return test;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(name, test);
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Fruit) {
            Fruit other = (Fruit) o;
            return name.equals(other.name) && test.equals(other.test);
        }

        return false;
    }
}

NameConverter.java:

package org.acme.hibernate.orm;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter
public class NameConverter implements AttributeConverter<String, String> {

    @Override
    public String convertToDatabaseColumn(String name) {
        return "a" + name;
    }

    @Override
    public String convertToEntityAttribute(String name) {
        return name.substring(1);
    }

}