以前曾有人问过这个问题,但我还没有找到任何适合我的用例的答案。 我创建了一个简化的玩具示例来解释我的问题。 想象我们有一个
Customer
和 Purchase
实体:
@Entity
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
protected Customer() {}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
@Entity
public class Purchase {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(name = "item_name")
private String itemName;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@ManyToOne
@JoinColumns({
@JoinColumn(updatable=false, insertable=false, name="first_name", referencedColumnName="first_name"),
@JoinColumn(updatable=false, insertable=false, name="last_name", referencedColumnName="last_name")
})
Customer customer;
public Customer getCustomer() { return customer; }
public void setCustomer(Customer customer) { this.customer = customer; }
public void setID(Long id) { this.id = id; }
public Long getID() { return this.id; }
protected Purchase() { }
public Purchase(String itemName, String firstName, String lastName) {
this.itemName = itemName;
this.firstName = firstName;
this.lastName = lastName;
}
}
如您所见,购买使用两列连接到客户:客户的名字和姓氏(我知道这有点人为,因为最好连接客户 ID)。 问题是当我尝试更新现有购买时。如果购买详细信息发生更改,我会创建一个全新的购买,设置此新购买的 ID 字段,然后保存新购买,该新购买将覆盖旧购买,因为它们具有相同的 ID。
customerRepository.save(new Customer("firstName", "lastName"));
purchaseRepository.save(new Purchase("itemName", "firstName", "lastName"));
Purchase p1 = purchaseRepository.findAll().get(0);
Purchase p2 = new Purchase("updatedItemName", "firstName", "lastName");
p2.setID(p1.getID());
purchaseRepository.save(p2);
但是,这总是会产生此警告:
2022-07-22 21:04:22.088 WARN 46139 --- [ main] o.h.p.entity.AbstractEntityPersister : HHH000502: The [customer] property of the [com.example.accessingdatajpa.Purchase] entity was modified, but it won't be updated because the property is immutable.
我需要帮助来防止出现此警告。
我知道我可以用
p1
的数据更新 p2
,但问题是在我的实际代码中,购买有很多字段,如果可能的话,我想避免手动设置每个字段。
如果有人有更好的解决方案,我可以根据新记录更新旧记录(不指定要更新的列的名称),我很想看到该解决方案。
根据两种情况,可以通过两种方式解决。
场景 1: 客户属性未直接映射到数据库列,而任何其他列均未从中派生。
此场景的解决方案:删除
updatable=false, insertable=false
列定义。您的代码应如下所示:
@ManyToOne
@JoinColumns({
@JoinColumn(name="first_name", referencedColumnName="first_name"),
@JoinColumn(name="last_name", referencedColumnName="last_name")
})
private Customer customer;
场景 2: 客户属性直接映射到数据库列,而任何其他列均从中派生。
此场景的解决方案:修改Customer列添加新列,
@ManyToOne(targetEntity = Customer.class, fetch = FetchType.EAGER)
@JoinColumns({
@JoinColumn(name="first_name", referencedColumnName="first_name"),
@JoinColumn(name="last_name", referencedColumnName="last_name")
})
private Customer customer;
@Column(updatable=false, insertable=false, name = "customer_id")
private long customerId;
希望这对您有帮助。