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");
}
}
我看到 testUpdateNameOnly
和 testUpdateNameOnlyREST
失败,而其他测试 运行 符合预期。在我原来的测试用例中,即使更改另一个字段也不会更新 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);
}
}
我使用 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");
}
}
我看到 testUpdateNameOnly
和 testUpdateNameOnlyREST
失败,而其他测试 运行 符合预期。在我原来的测试用例中,即使更改另一个字段也不会更新 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);
}
}