【问题标题】:How to update object hibernate如何更新对象休眠
【发布时间】:2019-11-14 15:16:55
【问题描述】:

我在将对象从 java 代码更新到 postgresql 时遇到问题。 当我更新对象时,我遇到了 id 问题,因为 id 为空。因此在数据库中创建一个新行而不是覆盖同一行。 看起来,数据库中的行:

id = 1
name = "name"
then I'm sending a json, like:
{
  name: "newName"
}

然后我得到了新行,看起来:

id = 1, name = "name"
id = 2, name = "newName"

这是因为当我发送 json 时,id 为空,所以 postgresql 正在创建一个新行,但我想用 id = 1 覆盖该行。添加@OneToOne(orphanRemoval = true) 的解决方案之一,但我不喜欢它,因为它会删除旧的 id 然后创建新的 id。如果我没有 id,如何覆盖初始行?

谢谢!

class A{
@Id
@GeneratedValue
UUID id;

@OneToOne(mappedBy = "A", cascade = CascadeType.ALL)
B b;
}

class B{
 @Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;

@OneToOne(optional = false)
@JoinColumn(name = "A_id")
A a;
}

updatedA.setInfo(jsonSend.getInfo());

【问题讨论】:

  • 解决这个问题的关键是你需要告诉数据库哪条记录正在被更新。您可以通过提供要更新的记录的 id 或任何其他可以唯一标识记录的字段来做到这一点。
  • 发布处理 JSON(Spring MVC 控制器?)并尝试保存到数据库的代码。

标签: java postgresql hibernate spring-boot jpa


【解决方案1】:

在这之间,我用“spring beanutils copyproperties”解决了我的问题,也许它对某人有帮助。

【讨论】:

    【解决方案2】:

    我正在使用 CrudRepository。 那么部分代码,实体:

      public class Human {
    
      @Id
      @GeneratedValue
      Long id;
    
      @Column(name = "first_name")
      String firstName;
    
      @Column(name = "last_name")
      String lastName;
    
      @JoinColumn(name = "data_document_id")
      @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
      @OneToOne(cascade = CascadeType.PERSIST)
      DataDocument dataDocument;
    
      @OneToMany(mappedBy = "human", cascade = CascadeType.ALL)
      @Singular
      List<Book> books;
    
    }
    
    
    
      public class DataDocument {
    
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      Long id;
    
      String name;
     }
    
    
    
    public class Book {
    
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      Long id;
    
      Boolean isReaded;
    
      Integer type;
    
      Integer cost;
    
      Instant date;
    }
    

    这里我做 POST 来创建一个人:

    {
      "firstName": "firstName",
      "lastName": "lastName",
      "dataDocument": {
          "name": "randomDocument"
        },
      "books": [
        {
          "isReaded": true,
          "type": 0,
          "cost": 100,
          "date": "2019-06-11"
        }
      ]
    }
    
    
    humanRepository.save(human);
    

    所以没关系,我必须获取数据库中的行:

    TABLE HUMAN
    human_id = 1, firstName = firstName, lastName = lastName, data_document_id = 1
    
    TABLE DOCUMENT_DATA
    data_document_id = 1, name = randomDocument
    
    TABLE BOOK
    book_id = 1, human_id = 1, type = 0, cost = 100, date = "2019-06-11", isReaded = true
    

    然后我想更新我的人类。例如json:

    {
      "id": 1,
      "firstName": "firstName",
      "lastName": "lastName",
      "dataDocument": {
          "name": "NEW_DOCUMENT"
        },
      "books": [
        {
          "isReaded": true,
          "type": 0,
          "cost": 100,
          "date": "2019-06-11"
        }
      ]
    }
    

    我的方法:

      public Human updateHuman(Long humanId, updateHuman){
        Human human = humanRepository.findById(humanId);
        human.setDocumentData(updateHuman.getDocumentData());
        humanRepository.save(human);
      }
    

    那么在表格中,我会得到:

    TABLE HUMAN
    human_id = 1, firstName = firstName, lastName = lastName, data_document_id = 2
    
    TABLE DOCUMENT_DATA
    data_document_id = 1, name = randomDocument
    data_document_id = 2, name = NEW_DOCUMENT
    

    这就是问题所在。我想将 data_document_id = 1 覆盖为新名称。我知道一些解决方案,例如

     @OneToOne(orphanRemoval = true) 
    但它会给出下一个结果:
    TABLE DOCUMENT_DATA
    data_document_id = 2, name = NEW_DOCUMENT
    

    我也可以这样写代码:

      public Human updateHuman(Long humanId, updateHuman){
        Human human = humanRepository.findById(humanId);
        Long id = human.getDocumentData().getId();
        human.setDocumentData(updateHuman.getDocumentData());
        human.getDocumentData().setId(id);
        humanRepository.save(human);
      }
    

    那么它就可以正常工作了。但是我有 40 个字段,其中 10 个是列表,其中 10 个是另一个字段太多的实体。 我只想找到更新对象的最简单方法。我考虑过查询,但我不确定它是否会起作用。 只是我有一个 HUMAN 到 UPDATED_SOME_FIELDS = HUMAN_WITH_UPDATED_SOME_FIELDS。

    【讨论】:

      【解决方案3】:

      将 id 发送给客户端,当它调用 put/post 时,将其发回。如果没有它,您将不知道应该更新哪个记录(这是常规解决方案)。 其他解决方案,如果名称是唯一/自然 ID(我不这么认为),您也可以发布旧名称和新名称。然后选择旧名称的记录,更新对象并保存。

      【讨论】:

      • 好吧,当我调用 put/post 时,我不知道 id。我只有@OneToOne 与另一个表相关的对象。例如,我有一个人类 {"firstName": "name", "document": { "name": "passport" },}。然后在数据库中,我得到 Human id=1,firstName=name,document_id=3。在我调用数据库的人之后,humanRepository.findById(1)。然后客户端发送更新,{"id"=1, "firstName": "name", "document": { "name": "randomDocument" },}。然后我只是得到一个新的行。但我们知道,id = 1 的用户,更改他的文档。
      • 如果是onetoone关系,直接选择parent get children,更新child的propr字段,然后保存即可。
      • 我正在这样做,但它不会覆盖 id,它会创建一个新的 id。如果我的“randomDocument”有 id = 1,那么如果我更新“randomDocument2”将得到 id = 2,并且人类将与 id = 2 相关,但我想覆盖 id = 1。
      • 您可以将您的保存代码(和其他相关代码)复制到 pastebin 并在此处链接吗?
      • 问题是你为你的实体设置了一个新的数据文档 human.setDocumentData(updateHuman.getDocumentData());|您应该获取文档: DocumentData dd=human.setDocumentData() 然后在大多数情况下设置正确的字段 dd.setName(YourNewName),mapstruct 等映射器比手动操作更好
      猜你喜欢
      • 2014-09-20
      • 1970-01-01
      • 2013-02-22
      • 1970-01-01
      • 1970-01-01
      • 2012-08-09
      • 1970-01-01
      • 2011-10-11
      • 2016-04-04
      相关资源
      最近更新 更多