JpaRepository save()创建新的子对象,而不是更新 [英] JpaRepository save() creating new child objects instead of updating

查看:476
本文介绍了JpaRepository save()创建新的子对象,而不是更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用GSON将以下JSON转换为两个java对象. Company对象包含一对一关系的Accounts对象.

I am currently converting the below JSON into two java objects using GSON. The Company object contains an Accounts object in a one-to-one relationship.

JSON:

{
  "company_name": "ETHEREUM LTD",
  "accounts": {
    "next_made_up_to": "2018-11-30",
    "next_due": "2019-08-31"
  },
  "company_number": "11090535"
}

公司对象:

@Data
@Entity
@Table(name = "companies")
public class Company {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne(cascade=CascadeType.ALL)
    private Accounts accounts;

    @NotNull
    @SerializedName("company_number")
    @Column(unique = true)
    private String companyNumber;

    @SerializedName("company_name")
    private String companyName;

    public Company() {}

    public Company(String companyNumber) {
        this.companyNumber = companyNumber;
    }
}

帐户对象:

@Data
@Entity
@Table(name = "accounts")
public class Accounts {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @SerializedName("next_due")
    private Date nextDue;

    @SerializedName("next_made_up_to")
    private Date nextMadeUpTo;
}

我已经实现了一个Spring Data JpaRepository来将这些对象保存到我的数据库中.

I have implemented a Spring Data JpaRepository to save these objects to my database.

public interface CompanyRepository extends JpaRepository<Company, Long> {
}

我有一种方法可以使用新的JSON信息更新数据库中的所有Company对象.

I have a method to update all Company objects in the database with new JSON information.

@Scheduled(fixedRate = 50000)
public void updateAllCompanies() {
    System.out.println("Starting update!");
    for(Company company : companyRepository.findAll()) {
        Long companyId = company.getId();
        Long accountsId = null;
        if(company.getAccounts() != null) {
            accountsId = company.getAccounts().getId();
        }
        company = getCompany(company.getCompanyNumber());
        company.setId(companyId);
        if(accountsId != null) {
            company.getAccounts().setId(accountsId);
        }
        companyRepository.save(company);
    }
}

除非我在父对象和子对象上都手动设置了ID,否则这些对象将被创建为新的数据库条目,而不是更新现有的条目.有比手动在Java中设置ID更好的方法吗?

Unless I manually set the ids on both the parent and child object, these objects are created as new database entries rather than updating existing entries. Is there a better way of handling this than manually setting the ids in Java?

推荐答案

除非我在父对象和子对象上都手动设置了ID,否则这些对象将被创建为新的数据库条目,而不是更新现有的条目.

Unless I manually set the ids on both the parent and child object, these objects are created as new database entries rather than updating existing entries.

这就是每个持久性提供程序的工作方式.

That is how every persistence provider works.

如果实体的@Id字段未标记为由持久性提供程序或数据库自动生成,则空值的存在将触发提供程序引发异常.但是,如果将该字段标记为由提供者或数据库自动生成,则它将跳过该异常,并将实体视为必须插入的新实例.只有在标识符字段中存在值的情况下,才会触发对现有行的更新.

If the @Id field of an entity isn't marked to be auto-generated by the persistence provider or the database, then the presense of a null-value will trigger the provider to throw an exception. However if the field is marked to be auto-generated by the provider or the database, it will skip the exception and treat the entity as a new instance that must be inserted. Only under the existence of a value in the identifier field will trigger an update to an existing row.

有比在Java中手动设置ID更好的方法吗?

Is there a better way of handling this than manually setting the ids in Java?

那要看.

如果JSON有效负载可以为您提供id值,则可以简单地将其序列化到对象中,并且持久性过程将像手动分配它们一样工作.这意味着具有标识符值的实体将被更新,没有标识符的实体将被插入.

If the JSON payload can provide you with the id values, you can simply serialize those into the objects and the persistence process would work just like you manually assigning them. This means entities that have identifier values will be updated, those without will be inserted.

如果这不是一个可行的选择,那么如果您打算使用@Entity代表您的Accounts,则需要分配它们.

If that isn't a plausible option, then you're going to need to assign them if you intend to use an @Entity to represent your Accounts.

我不确定您的Accounts实体是否被数据模型中的任何其他内容引用.但是这里要考虑的一件事是@ElementCollection的可嵌入对象多么强大,也可以非常轻松地解决您的标识符问题:

I'm not sure if your Accounts entity is references by anything else in your data model. But one thing to consider here is how powerful an @ElementCollection of embeddables could very easily solve your identifier problem too:

@Embeddable 
public class Accounts implements Serializable {
  private Date nextDue;
  private Date nextMadeUpTo;
  // implement proper equals/hashcode here
}

@Entity
public class Customer {
  // your normal things
  @ElementCollection
  private Set<Accounts> Accounts;
}

现在您需要做的就是将JSON获取的所有数据添加到Accounts中,并将其放入element-collection中.然后,Hibernate将使用以下收集表来确定是否需要为您删除或插入某些内容:

Now all you need to do is add whatever data your JSON gets into an Accounts and place it into the element-collection. Hibernate will then take care of determining whether or not something needs to be removed or inserted for you by using a collection-table like the following:

CUSTOMER_ID | NEXT_DUE | NEXT_MADE_UP_TO

Accounts可嵌入的内容上正确使用equals/hashCode可以保证没有重复,这也有助于确定是否进行了修改.现在,基础收集表将可嵌入键+ Customer主键的所有字段用作表的主键.通过将数据用作自然键,可以避免代理主键出现问题.

The proper using of equals / hashCode on the Accounts embeddable guarantees no duplicates, it also helps determine what is modified or not too. The underlying collection-table now uses all fields of the embeddable + the Customer primary key as the table's primary key. This avoids the problem with a surrogate primary key by using as the data as natural keys.

这篇关于JpaRepository save()创建新的子对象,而不是更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆