我有三個類:WorkPosition,Employee和EmployeeCode。Employee代表在某處作業的人,employee可以有多個(作業)職位,employee的code代表雇員(一個或多個code)。對于每個 WorkPosition,defaultCode必須分配一個默認的 EmployeeCode(欄位),如果員工有任何代碼,則顯示哪個代碼代表該職位的員工。
Employee->WorkPosition是一對多的關系Employee->EmployeeCode是一對多的關系EmployeeCode->WorkPosition是一對多的關系
WorkPosition 班級:
@Entity
@Table(name = "work_position")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class WorkPosition{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_generator")
@SequenceGenerator(name = "sequence_generator")
private Long id;
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@NotNull
private Employee employee;
@ManyToOne(fetch = FetchType.LAZY)
private EmployeeCode defaultCode;
// other fields, getters, setters, equals and hash ...
Employee 班級:
@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_generator")
@SequenceGenerator(name = "sequence_generator")
private Long id;
@OneToMany(mappedBy = "employee", fetch = FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<EmployeeCode> employeeCodes;
@OneToMany(mappedBy = "employee", fetch = FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<WorkPosition> workPositions;
// other fields, getters, setters, equals and hash ...
EmployeeCode 班級:
@Entity
@Table(name = "employee_code")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class EmployeeCode {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence_generator")
@SequenceGenerator(name = "sequence_generator")
private Long id;
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@NotNull
private Employee employee;
@OneToMany(mappedBy = "defaultCode", fetch = FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<WorkPosition> defaultCodes;
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (!(o instanceof EmployeeCode)) {
return false;
} else {
return this.id != null && this.id.equals(((EmployeeCode)o).id);
}
}
// other fields, getters, setters, hash ...
So, in my example, the only difference between one Employee's WorkPositions is the defaultCode, that may differ between WorkPositions.
I have a form, where I can manipulate all data related to a WorkPosition. For example, I can change the defaultCode of the WorkPosition and/or delete an EmployeeCode. When I save the form, I must check if an EmployeeCode was deleted that was set as defaultCode for any of the WorkPositions related to the saved WorkPosition. If so, I reassign it, otherwise I wouldn't be able to delete the EmployeeCode as I would get a ConstraintViolationException as the WorkPosition would be still referencing the EmployeeCode I wish to delete.
Let's say I have an Employee with two EmployeeCodes (EC1 and EC2) and two WorkPositions (WP1 and WP2). DefaultCode of WP1 is EC1 and defaultCode of WP2 is EC2. I save the form of WP1, but I do not delete anything. To check if the defaultCode (EC2) of a related WorkPosition (WP2) still exists, I loop over all the remaining codes (savedWorkPosition.getEmployeeCodes() where savedWorkPosition equals to WP1) and check whether it still contains the defaultCode (relatedWorkPosition.getDefaultCode() where relatedWorkPosition is queried from db and it references EC2).
newDefaultCode = savedWorkPosition.getEmployeeCodes() // [EC1, EC2]
.stream()
.filter(code -> code.equals(relatedWorkPosition.getDefaultCode()))
.findFirst()
.orElseGet(() -> ...);
However, the equals() (look at the EmployeeCode class above) returns false. When I debugged the equals method, I found out that the id of the parameter object (EC2) is null. When I log out the id in the filter call before the equals, I get the correct id. I could do .filter(code -> code.getId().equals(relatedWorkPosition.getDefaultCode().getId())) and it works, but this seems wrong. Why is the id in the equals method null?
I think it might be to do something with the state of the entity in the persistance context and Hibernate does something I do not understand. I used some help from this answer to log out the state of the entities:
entityManager.contains(relatedWorkPosition.getDefaultCode())returnstrueentityManagerFactory.getPersistenceUnitUtil().getIdentifier(relatedWorkPosition.getDefaultCode())returns correct id.entityManager.contains(<any code in savedWorkPosition.getEmployeeCodes()>)returnsfalseentityManagerFactory.getPersistenceUnitUtil().getIdentifier(<any code in savedWorkPosition.getEmployeeCodes()>)returns correct id.
uj5u.com熱心網友回復:
為什么equals方法中的id為null?
我將根據您之前所說的提供我的答案(因為,我自己也經歷過這樣的事情):
但是,equals()(查看上面的 EmployeeCode 類)回傳 false。在除錯equals方法時,發現引數物件(EC2)的id為null。當我在 equals 之前注銷過濾器呼叫中的 id 時,我得到了正確的 id。我可以做 .filter(code -> code.getId().equals(relatedWorkPosition.getDefaultCode().getId())) 并且它有效,但這似乎是錯誤的......
問題是在類中使用@ManyToOne(fetch=lazy)和當前實作的等號的組合EmployeeCode......當您將ManyToOne關系宣告為lazy,并加載包含/包裝這種關系的物體時,hibernate 不會加載關系或物體,而是它注入一個從您的物體類擴展而來的代理類......代理類充當攔截器并僅在呼叫其宣告的方法時才從持久層加載真實的物體資料......
這是棘手的部分:用于此類代理創建的庫創建被攔截物體的精確副本,其中包括您在物體類中宣告的相同實體變數(所有這些都使用默認 JAVA 值初始化)......當您將此類代理傳遞給equals方法(公平地說,它可以是任何方法)并且該方法的邏輯訪問提供的引數中的實體變數,您將訪問代理的虛擬變數,而不是您想要/期望的虛擬變數。這就是您在實作中看到這種奇怪行為的原因equals......
為了解決這個問題并避免錯誤,根據經驗,我建議替換實體變數的使用,并在提供的引數上呼叫 getter 和 setter 方法……在您的情況下,它將是這樣的:
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (!(o instanceof EmployeeCode)) {
return false;
} else {
return this.id != null
&& this.id.equals(((EmployeeCode)o).getId());
}
}
你可能想知道為什么:
this.id != null && this.id.equals(((EmployeeCode)o).getId());
并不是:
this.getId() != null
&& this.getId().equals(((EmployeeCode)o).getId());
原因很簡單:假設equals呼叫該方法的java物件是一個代理/惰性物體......當你呼叫這樣的方法時,代理的邏輯加載真實的物體并equals在其上呼叫真實的方法......代理 EmployeeCode 類的符號表示可能如下所示(注意,這不是真正的實作,只是一個更好地理解概念的示例):
class EmployeeCodeProxy extends EmployeeCode {
// same instance variables as EmployeeCode ...
// the entity to be loaded ...
private EmployeeCode $entity;
....
public boolean equals(Object o) {
if (this.$entity == null) {
this.$entity = loadEntityFromPersistenceLayer();
}
return this.$entity.equals(o);
}
...
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/347722.html
標籤:java hibernate jpa spring-data-jpa
上一篇:為什么我會收到與使用Hibernate的PosgreSQL表的自動增量PK相關的錯誤?錯誤:關系“hibernate_sequence”不存在
下一篇:用戶創建的休眠識別符號問題
