2011-07-05 5 views
3

JPA를 처음 사용하기 때문에 캐스케이드 및 연결에 대한 충분한 지식이 부족하기 때문에 다음과 같은 문제가 발생합니까?엔티티를 업데이트 할 때 java.sql.SQLIntegrityConstraintViolationException이 발생했습니다.

@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 
    ... 
    } 

관계는 I는 각각 여러 번 perfomed되는 테스트 - (S)의 세트를 가지고 있다는 의미

@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 + " ]"; 
    } 
} 

: 그리고 ManyToOne 협회 - I는 양방향 OneToMany에 두 엔티티가 시간은 TestRun과 관련이 있습니다. 은을 TestRun를 만들려면, 나는 다음과 같은 방법을 사용 : 새로운 시험 (삽입)와 createTestRun의 거래, 테스트 객체가 올바르게 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; 
    } 
} 

.

.... 
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 (?, ?) 

이는 무대 뒤에서 무슨 일이 일어날 않습니다 테스트가 이미 JPA (내 경우는 EclipseLink)이 존재하는 경우 그러나 INSERT를 실행 어쨌든 시도? 문제가 Test의 appearOnTestRuns 속성과 관련이 있습니까? 왜 JPA는 Test가 DB에 이미 존재한다는 것을 이해하지 못합니다 (결국 find 연산 중에 id 속성이 설정되고 equals()는이 값을 사용하여 2 개의 테스트가 같은지 아닌지를 결정합니다) 감사합니다. ! :)

추 신 :이 개념들이 광범위하게 설명되어있는 훌륭한 튜토리얼/책을 알고 있습니까?

+0

EntityFactory.newTestRun (testPerformed) 코드를 표시 할 수 있습니까? –

+0

안녕하세요! 나는 방금 해냈다! :) 나는 DB에서 가져온 Test-s가 ejb.find()가 반환 된 후에 detatched 할 것이므로 새로운 TestRun 객체를 유지할 동일한 트랜잭션 내에서 수동으로 병합해야한다고 생각 했습니까? – Federico

+0

분리하지 마십시오. 전체 createTestRun 메소드는 단일 트랜잭션으로 실행되어야합니다. 트랜잭션은 원자 적 기능 변경에 사용되어야하며, 원자 쿼리 또는 데이터베이스에 대한 갱신에는 사용되지 않아야합니다. –

답변

0

우선, createTestRun 메서드 (테스트를 찾고 필요하면 생성 한 다음 TestRun 인스턴스를 생성하고 지속 함)가 단일 트랜잭션 내에서 실행되는지 확인해야합니다.

newTestRun 메서드는 양방향 인 관계의 양쪽을 초기화해야합니다. 엔터티 그래프의 일관성을 유지하는 것은 개발자의 책임입니다. 따라서 다음을 수행해야합니다.

public static TestRun newTestRun(Test test){ 
    TestRun run = new TestRun(); 
    run.setPerformedTest(test); 
    test.getAppearsOnTestRuns().add(run); 
    return run; 
} 
관련 문제