Я новичок в JPA, и у меня возникла следующая проблема, возможно, из-за недостаточного понимания каскада и ассоциаций?У меня есть две сущности, которые находятся в двунаправленной ассоциации OneToMany - ManyToOne:
@Entity
public class TestRun implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
public Long getId() {
return id;
}
public TestRun(){
}
public void setId(Long id) {
this.id = id;
}
@ManyToOne(optional=false, cascade={CascadeType.PERSIST, CascadeType.MERGE})
private Test performedTest;
public Test getPerformedTest() {
return performedTest;
}
public void setPerformedTest(Test performedTest) {
this.performedTest = performedTest;
}
.....
@Override
public boolean equals(Object object) {
if (!(object instanceof TestRun)) {
return false;
}
TestRun other = (TestRun) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "TestRun[ id=" + id + " ]";
}
}
И:
@Entity
public class Test implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Basic(optional=false)
@Column(nullable=false)
private String name;
@OneToMany(mappedBy="performedTest", cascade={CascadeType.MERGE, CascadeType.PERSIST})
private Collection<TestRun> appearsOnTestRuns;
public Collection<TestRun> getAppearsOnTestRuns() {
return appearsOnTestRuns;
}
public void setAppearsOnTestRuns(Collection<TestRun> appearsOnTestRuns) {
this.appearsOnTestRuns = appearsOnTestRuns;
}
//id based equals and hashcode
...
}
Отношение означает, что у меня есть набор тестов, которые выполняются несколькораз, каждый раз, будучи связанным с TestRun.Чтобы создать TestRun, я использую следующий метод:
public void createTestRun(String name){
Test testPerformed = ejb.findByName(name); //Returns null iff forTest is not in the DB--> INSERT new Test
if (testPerformed == null){
testPerformed = EntityFactory.newTest(name);//I set the name for test
}
TestRun run = EntityFactory.newTestRun(testPerformed);
ejb.persist(run);
}
public class EntityFactory{
public static TestRun newTestRun(Test test){
TestRun run = new TestRun();
run.setPerformedTest(test);
return run;
}
public static Test newTest(String name){
Test test = new Test();
test.setName(name);
return test;
}
}
, когда createTestRun имеет дело с новым Test (вставка), объект Test корректно сохраняется и TestRun.Но когда тест уже существует, JPA (EclipseLink в моем случае) все равно пытается выполнить INSERT:
....
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL110705102925930' defined on 'TEST'.
Error Code: -1
Call: INSERT INTO TEST (ID, NAME) VALUES (?, ?)
Что происходит за кулисами?Связана ли проблема со свойством emerge свойства TestOnTestRuns?Почему JPA не понимает, что Test уже существует в БД (в конце концов, свойство id устанавливается во время операции поиска, и equals () использует это значение, чтобы определить, равны ли 2 теста ...) Большое спасибо за вашу помощь!:)
PS: Знаете ли вы хороший учебник / книгу, где эти понятия подробно объясняются?