使用Quarkus和PanacheRepository更新实体数据无法正常工作。

huangapple go评论68阅读模式
英文:

Update entity data using Quarkus and PanacheRepository is not working

问题

我正在使用 Quarkus 和 PanacheRepository 进行一些测试,但在更新实体数据时遇到了问题。更新操作无法正常工作,字段的值没有被更新。

简而言之:我创建了一个实体并将数据持久化,然后在另一个请求中,我通过 repository.findById(id) 从数据库获取实体,更改了一些字段的值,但是新值没有持久化到数据库中。我尝试在此之后调用 repository.persist(person),但行为仍然相同,数据没有更新。

我尝试了 Quarkus 版本 1.9.0.Final、1.9.0.CR1、1.8.3.Final。

我正在使用 PostgreSQL 12。我还尝试了 MySQL 5.7.26。

我使用 Eclipse 2020-06(4.16.0)仅用于编写代码,并在命令行中运行应用程序,使用命令:./mvnw compile quarkus:dev

我创建了一个全新的简单应用程序,但行为仍然相同。以下是主要配置和一些代码片段:

pom.xml

<!-- 省略部分 -->

application.properties:

quarkus.datasource.db-kind = postgresql
quarkus.datasource.username = 用户名
quarkus.datasource.password = 密码
quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/testpanache

# 在启动时删除并重新创建数据库(使用 `update` 仅更新模式)
quarkus.hibernate-orm.database.generation = drop-and-create

实体:

@Entity
public class Person {

	@Id @GeneratedValue public Long id;
	
	public String name;

	@Override
	public String toString() {
		return "Person [id=" + id + ", name='" + name + "']";
	}	
}

REST 资源:

@Path("/people")
@Produces(MediaType.APPLICATION_JSON)
public class PersonResource {

	@Inject
	PersonRepository repository;
	
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public List<Person> hello() {
        return repository.listAll();
    }
    
    @POST
    @Transactional
    public void create() {
    	Person person = new Person();
    	person.name = "some name";
    	repository.persist(person);
    }

    @PUT
    @Path("{id}")
    @Transactional
    public Person update(@PathParam("id") Long id) {
    	Person person = repository.findById(id);
    	person.name = "updated updated updated"; // 无效
//    	repository.persist(person); // 无效
//    	repository.persistAndFlush(person); // 无效
    	repository.getEntityManager().merge(person); // 无效
    	return person;
    }
}

Repository:

@ApplicationScoped
public class PersonRepository implements PanacheRepository<Person> {
}

我使用 curl 发出了一些请求来演示此行为:

$ curl -w "\n" http://localhost:8080/people
[]

$ curl -X POST http://localhost:8080/people

$ curl -w "\n" http://localhost:8080/people
[{"id":1,"name":"some name"}]

$ curl -X PUT http://localhost:8080/people/1
{"id":1,"name":"updated updated updated"}

$ curl -w "\n" http://localhost:8080/people
[{"id":1,"name":"some name"}]

所以,列表开始为空,第二个 POST 请求创建了一个带有 "some name" 的 Person,如第三个请求所示;第四个请求执行了一个 PUT 操作,旨在将名称更改为 "updated updated updated",但第五个请求显示名称未更新。

虽然这并不是必要的,但我尝试将实体扩展为 PanacheEntity,并使用 Person.findById(id) 来查找实体,这样后续的更新操作确实生效了。但这不是我的重点,我想使用 PanacheRepository,并且想要了解我漏掉了什么。

英文:

I'm doing some tests with Quarkus and PanacheRepository and I'm getting trouble in update an entity data. The update doesn't work, the field values are not updated.

In short: I create an entity and persist the data, after that in another request I get the entity from database using repository.findById(id);, change some field value, but the new value is not persisted in the database. I tried call repository.persist(person); after but the behavior is the same, the data is not updated.

I tried this with Quarkus version 1.9.0.Final, 1.9.0.CR1, 1.8.3.Final

I'm using postgreSQL 12. I also tried with mysql 5.7.26

I use Eclipse 2020-06 (4.16.0) only to write code and I run the application in the command line, with: ./mvnw compile quarkus:dev

I've created a brand new simple application and the behavior is the same. Here is the main configurations and some code snippets:

pom.xml

	&lt;properties&gt;
		&lt;compiler-plugin.version&gt;3.8.1&lt;/compiler-plugin.version&gt;
		&lt;maven.compiler.parameters&gt;true&lt;/maven.compiler.parameters&gt;
		&lt;maven.compiler.source&gt;11&lt;/maven.compiler.source&gt;
		&lt;maven.compiler.target&gt;11&lt;/maven.compiler.target&gt;
		&lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
		&lt;project.reporting.outputEncoding&gt;UTF-8&lt;/project.reporting.outputEncoding&gt;
		&lt;quarkus-plugin.version&gt;1.9.0.Final&lt;/quarkus-plugin.version&gt;
		&lt;quarkus.platform.artifact-id&gt;quarkus-universe-bom&lt;/quarkus.platform.artifact-id&gt;
		&lt;quarkus.platform.group-id&gt;io.quarkus&lt;/quarkus.platform.group-id&gt;
		&lt;quarkus.platform.version&gt;1.9.0.Final&lt;/quarkus.platform.version&gt;
		&lt;surefire-plugin.version&gt;3.0.0-M5&lt;/surefire-plugin.version&gt;
	&lt;/properties&gt;
	&lt;dependencies&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;io.quarkus&lt;/groupId&gt;
			&lt;artifactId&gt;quarkus-resteasy-jsonb&lt;/artifactId&gt;
		&lt;/dependency&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;io.quarkus&lt;/groupId&gt;
			&lt;artifactId&gt;quarkus-hibernate-orm-panache&lt;/artifactId&gt;
		&lt;/dependency&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;io.quarkus&lt;/groupId&gt;
			&lt;artifactId&gt;quarkus-jdbc-postgresql&lt;/artifactId&gt;
		&lt;/dependency&gt;
	&lt;/dependencies&gt;

application.properties:

quarkus.datasource.db-kind = postgresql
quarkus.datasource.username = theusername
quarkus.datasource.password = thepassword
quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/testpanache

# drop and create the database at startup (use `update` to only update the schema)
quarkus.hibernate-orm.database.generation = drop-and-create

Entity:

@Entity
public class Person {

	@Id @GeneratedValue public Long id;
	
	public String name;

	@Override
	public String toString() {
		return &quot;Person [id=&quot; + id + &quot;, name= &#39;&quot; + name + &quot;&#39;]&quot;;
	}	
}

REST Resource:

@Path(&quot;/people&quot;)
@Produces(MediaType.APPLICATION_JSON)
public class PersonResource {

	@Inject
	PersonRepository repository;
	
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public List&lt;Person&gt; hello() {
        return repository.listAll();
    }
    
    @POST
    @Transactional
    public void create() {
    	Person person = new Person();
    	person.name = &quot;some name&quot;;
    	repository.persist(person);
    }

    @PUT
    @Path(&quot;{id}&quot;)
    @Transactional
    public Person update(@PathParam(&quot;id&quot;) Long id) {
    	Person person = repository.findById(id);
    	person.name = &quot;updated updated updated&quot;; // does not work
//    	repository.persist(person); // does not work
//    	repository.persistAndFlush(person); // does not work
    	repository.getEntityManager().merge(person); // does not work
    	return person;
    }
}

Repository:

@ApplicationScoped
public class PersonRepository implements PanacheRepository&lt;Person&gt; {
}

I made some requests using curl to demonstrate the behavior:

$ curl -w &quot;\n&quot; http://localhost:8080/people
[]

$ curl -X POST http://localhost:8080/people

$ curl -w &quot;\n&quot; http://localhost:8080/people
[{&quot;id&quot;:1,&quot;name&quot;:&quot;some name&quot;}]

$ curl -X PUT http://localhost:8080/people/1
{&quot;id&quot;:1,&quot;name&quot;:&quot;updated updated updated&quot;}

$ curl -w &quot;\n&quot; http://localhost:8080/people
[{&quot;id&quot;:1,&quot;name&quot;:&quot;some name&quot;}]

So, the list starts empty, the second POST request creates a Person with "some name", as shown by the third request; the fourth request does a PUT that is intended to change the name to "updated updated updated", but the fifth request shows the name was not updated.

Although it's not needed, I tried repository.persist(person);, repository.persistAndFlush(person);, and even repository.getEntityManager().merge(person); (one each time) as show in the PersonResource snippet above. But none of them made effect.

What I am missing?

PS.: I tried to change my entity to extends PanacheEntity and used Person.findById(id); to find the entity, this way the subsequent updates did make effect. But it's not my point, I wanna use PanacheRepository and want to understand what I'm missing with this.

答案1

得分: 7

请考虑使用getter/setter访问您的实体,以便Hibernate代理能够正常工作。

@Entity
public class Person {

    @Id @GeneratedValue public Long id;

    private String name;  // &lt;--- 私有字段

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

    @Override
    public String toString() {
        return "Person [id=" + id + ", name= '" + name + "']";
    }
}

并且在您的资源类中:

    @PUT
    @Path("{id}")
    @Transactional
    public Person update(@PathParam("id") Long id) {
        Person person = repository.findById(id);
        person.setName("updated updated updated");  // &lt;--- 这种方式有效
        repository.persist(person);
        return person;
    }
英文:

Please consider accessing your entity using getter/setter, so Hibernate Proxies will work properly.

@Entity
public class Person {

    @Id @GeneratedValue public Long id;
    
    private String name;  // &lt;--- private field

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

    @Override
    public String toString() {
        return &quot;Person [id=&quot; + id + &quot;, name= &#39;&quot; + name + &quot;&#39;]&quot;;
    }   
}

and in your resource:


    @PUT
    @Path(&quot;{id}&quot;)
    @Transactional
    public Person update(@PathParam(&quot;id&quot;) Long id) {
        Person person = repository.findById(id);
        person.setName(&quot;updated updated updated&quot;);  // &lt;--- this way works
        repository.persist(person);
        return person;
    }

huangapple
  • 本文由 发表于 2020年10月24日 00:33:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/64503946.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定