CRUD API Spring Boot 复制条目

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

CRUD API Spring Boot Make a Copy of an entry

问题

以下是您提供的内容的翻译部分:

我正在尝试从CRUD存储库中获取的实例创建副本我想存储实例的副本但使用不同的主键在服务类中的复制方法中当我尝试创建副本时会抛出错误错误信息为**`org.hibernate.HibernateException将SpringBootStarter.Topic.Topic的实例的标识符从<id>更改为<new_id>`**在制作副本后当我在Postman上发出GET请求时我希望在结果中同时看到原始实例和副本但副本具有不同的主键)。

有人可以帮帮我吗

以下是控制器类

@RestController
public class TopicController {

    @Autowired
    private TopicService topicService;

    @GetMapping("/topics")
    public List<Topic> getAllTopics(){
        return topicService.getAllTopics();
    }

    @GetMapping("/topics/{id}")
    public Topic getTopic(@PathVariable String id){
        return topicService.getTopic(id);
    }

    @PostMapping("/topics")
    public void addTopic(@RequestBody Topic topic){
        topicService.addTopic(topic);
    }

    @PostMapping("topics/{id}/{new_id}")
    public void copyTopic(@PathVariable String id, @PathVariable String new_id){
        topicService.copyTopic(id, new_id);
    }

    @PutMapping("/topics/{id}")
    public void updateTopic(@RequestBody Topic topic, @PathVariable String id){
        topicService.updateTopic(topic, id);
    }

    @DeleteMapping("/topics/{id}")
    public void deleteTopic(@PathVariable String id){
        topicService.deleteTopic(id);
    }
}

以下是服务类:

@Service
public class TopicService {

@Autowired
private TopicRepository topicRepository;
public List<Topic> getAllTopics(){
List<Topic> topics = new ArrayList<>();
topicRepository.findAll().forEach(topics::add);
return topics;
}
public Topic getTopic(String id){
Optional<Topic> optional = topicRepository.findById(id);
return optional.get();
}
public void addTopic(Topic topic){
topicRepository.save(topic);
}
public void copyTopic(String id, String new_id){
Topic topic = topicRepository.findById(id).get();
Topic topicCopy = topic;
topicCopy.setId(new_id);
addTopic(topicCopy);
}
public void updateTopic(Topic topic, String id){
topicRepository.save(topic);
}
public void deleteTopic(String id){
topicRepository.deleteById(id);
}

}


以下是主题存储库:
```java
public interface TopicRepository extends CrudRepository<Topic, String> {
}
英文:

I am trying to make a copy of an instance which I am fetching from a CRUD Repository. I want to store the copy of an instance but with a different primary key. In the copy method which I have made in the service class, when I try to make a copy, it throws an error saying org.hibernate.HibernateException: identifier of an instance of SpringBootStarter.Topic.Topic was altered from &lt;id&gt; to &lt;new_id&gt; When I hit a GET request on postman after making the copy, I want to see both the original and the copy in the result (but the copy with a different primary key.)

Can somebody please help me?


import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Topic {
@Id
private String id;
private String name;
private String description;
public Topic(){
}
public Topic(String id, String name, String description) {
this.id = id;
this.name = name;
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

Below is the Controller Class


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class TopicController {
@Autowired
private TopicService topicService;
@GetMapping(&quot;/topics&quot;)
public List&lt;Topic&gt; getAllTopics(){
return topicService.getAllTopics();
}
@GetMapping(&quot;/topics/{id}&quot;)
public Topic getTopic(@PathVariable String id){
return topicService.getTopic(id);
}
@PostMapping(&quot;/topics&quot;)
public void addTopic(@RequestBody Topic topic){
topicService.addTopic(topic);
}
@PostMapping(&quot;topics/{id}/{new_id}&quot;)
public void copyTopic(@PathVariable String id, @PathVariable String new_id){
topicService.copyTopic(id, new_id); }
@PutMapping(&quot;/topics/{id}&quot;)
public void updateTopic(@RequestBody Topic topic, @PathVariable String id){
topicService.updateTopic(topic, id);
}
@DeleteMapping(&quot;/topics/{id}&quot;)
public void deleteTopic(@PathVariable String id){
topicService.deleteTopic(id);
}
}

Below is the Service Class

package SpringBootStarter.Topic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
public class TopicService {
@Autowired
private TopicRepository topicRepository;
public List&lt;Topic&gt; getAllTopics(){
List&lt;Topic&gt; topics = new ArrayList&lt;&gt;();
topicRepository.findAll().forEach(topics :: add);
return topics;
}
public Topic getTopic(String id){
Optional&lt;Topic&gt; optional = topicRepository.findById(id);
return optional.get();
}
public void addTopic(Topic topic){
topicRepository.save(topic);
}
public void copyTopic(String id, String new_id){
Topic topic = topicRepository.findById(id).get();
Topic topicCopy = topic;
topicCopy.setId(new_id);
addTopic(topicCopy);
}
public void updateTopic(Topic topic, String id){
topicRepository.save(topic);
}
public void deleteTopic(String id){
topicRepository.deleteById(id);
}
}

Below is the Topic Repository


import org.springframework.data.repository.CrudRepository;
public interface TopicRepository extends CrudRepository&lt;Topic, String&gt; {
}

答案1

得分: 1

持久化上下文管理着所有实体的生命周期。当你获取一个实体时,它将成为事务内的一个附加实体。由于对象的引用不会改变,持久化上下文将会知道它仍然是数据库中的同一个对象,不允许它的标识符发生改变。
如果你想创建一个新条目,你将必须使用 new 关键字创建一个新对象,然后将其持久化。

因此,不要像这样改变标识符:

public void copyTopic(String id, String new_id){
    Topic topic = topicRepository.findById(id).get();
    Topic topicCopy = topic;
    topicCopy.setId(new_id);
    addTopic(topicCopy);
}

而应该创建一个新的 Topic 实体并像这样持久化:

public void copyTopic(String id, String new_id){
    Topic topic = topicRepository.findById(id).get();
    Topic topicCopy = new Topic(topic);
    topicCopy.setId(new_id);
    addTopic(topicCopy);
}

我的建议是要详细了解 Hibernate 的基础知识,因为在使用 ORM 时会有很多陷阱。在不理解基本原理的情况下开始使用 ORM 从来都不是一个好主意。

英文:

The persistence context holds the lifecycle of all entities. When you fetch an entity it will be an attached entity within that transsaction. Because the reference of your object does not change, the persistence context will know that it's still the same object in the database which does not allow it's identifier to change.
If you want to create a new entry, you will have to create a new object using the new keyword and persist that one.

So instead of changing the identifier like so

public void copyTopic(String id, String new_id){
Topic topic = topicRepository.findById(id).get();
Topic topicCopy = topic;
topicCopy.setId(new_id);
addTopic(topicCopy);
}

Create a new Topic entity and persist it like so

public void copyTopic(String id, String new_id){
Topic topic = topicRepository.findById(id).get();
Topic topicCopy = new Topic(topic);
topicCopy.setId(new_id);
addTopic(topicCopy);
}

My advice is to read up on the basics of Hibernate because there are a lot of pitfalls when using an ORM. It's never a good idea to start using one without understanding the very basics.

huangapple
  • 本文由 发表于 2020年9月30日 15:18:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/64132683.html
匿名

发表评论

匿名网友

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

确定