2010-11-30 4 views
0

시퀀스 번호가 혼합 된 대용 키 :JPA, 외래 키와 내가 두 테이블을 가지고

DOCUMENT 
-------- 
DOC_ID (PK) 
. 
. 
. 

SECTION 
------- 
DOC_ID (FK, PK) 
SECTION_NUM (PK) 
. 
. 
. 

데이터베이스의 항목은 다음과 같습니다

문서 :

DOC_ID | . . . 
-------------- 
1  | . . . 
2  | . . . 

섹션 :

DOC_ID | SECTION_NUM | . . . 
--------------------------- 
1  | 1   | . . . 
1  | 2   | . . . 
1  | 3   | . . . 
2  | 1   | . . . 

Document에는 DOC_ID에 생성 된 Id가 있고 Section에는 DOC_ID 및 SECTION_NUM에 복합 기본 키가 있습니다.

SECTION_NUM은 모든 문서에 대해 새로 시작하는 로컬 (응용 프로그램) 생성 시퀀스 번호입니다. 다음과 같이

내 엔티티 클래스

보일 : 나는 NULL을 알리는 예외가되지 얻을 지속되면

Document doc = new Document(); 

Section section = new Section(); 
section.setDocument(doc); 
section.setSectionNum(1); 

entityManager.persist(doc); 

:

@Entity 
@Table(name = "DOCUMENT") 
public class Document implements java.io.Serializable { 
    @Id 
    @Column(name = "DOC_ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "DocIdSeq") 
    @SequenceGenerator(name = "DocIdSeq", sequenceName = "DOC_ID_SEQ", allocationSize = 1) 
    private Long docId; 
} 


@Entity 
@Table(name = "SECTION") 
@IdClass(SectionId.class) 
public class Section implements java.io.Serializable { 
    @Id 
    @Column(name = "DOC_ID", nullable = false) 
    private Long docId; 

    @Id 
    @Column(name = "SECTION_NUM", nullable = false) 
    private Integer sectionNum; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "DOC_ID") 
    private Document document; 
} 

public class SectionId implements java.io.Serializable { 
    private Long docId; 
    private Integer sectionNum; 
} 

새로운 문서 및 관련 섹션을 삽입, 나는 다음을 수행 열 SECTION_NUM에 허용되었습니다. OpenEJB (OpenJPA를 사용하여 단위 테스트를위한 OpenJPA를 사용합니다)를 사용하고 OpenJPA 코드를 통해 Document 객체를 성공적으로 지속 할 때 발견되지만 Section 객체의 경우에는 새 인스턴스를 반영하여 만들고 모든 필드를 null로 설정하여 이전에 지속 된 Document 객체에 연결하기 전에 sectionNum 값을 잃어 버립니다.

불행히도 레거시 시스템이므로 DB 스키마를 변경할 수 없습니다. 아무도 비슷한 작업을 수행하고 작동시키지 않았습니까?

답변

0

나는 약간의 시간이 업데이트 했었어,하지만 너무 바빠서 ...

좋아, 그래서 이것이 JPA와 정말 수 없습니다 밝혀졌습니다. 그러나 해결 방법이 있습니다.

이전에 나는 Document 클래스가 이와 같이 보인다고 언급했습니다.

@Entity 
@Table(name = "DOCUMENT") 
public class Document implements java.io.Serializable { 
    @Id 
    @Column(name = "DOC_ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = 
    "DocIdSeq") 
    @SequenceGenerator(name = "DocIdSeq", sequenceName = "DOC_ID_SEQ", allocationSize = 1) 
    private Long docId; 
} 

이는 문제를 명확히하기위한 단순화 된 버전입니다. 진짜 클래스가 너무 섹션의 컬렉션이 있습니다 : 섹션은 간단한 기본 키를 가지고있는 경우는 응용 프로그램에서 ID를 적용하거나 시퀀스에서 발생하는 것처럼

@Entity 
@Table(name = "DOCUMENT") 
public class Document implements java.io.Serializable { 
    @Id 
    @Column(name = "DOC_ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = 
"DocIdSeq") 
    @SequenceGenerator(name = "DocIdSeq", sequenceName = "DOC_ID_SEQ", allocationSize = 1) 
    private Long docId; 

    @OneToMany 
    private Set<Section> sections = new HashSet<Section>(0); 
} 

는 JPA 쉽게 관계를 처리 할 것입니다, 그러나 그것은 하나의 이드와 함께 할 수 없습니다.

그래서,이 솔루션은 관계를 직접 관리 및 라이프 사이클 기능을 추가하는 것입니다

@Entity 
@Table(name = "DOCUMENT") 
public class Document implements java.io.Serializable { 
    @Id 
    @Column(name = "DOC_ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = 
    "DocIdSeq") 
    @SequenceGenerator(name = "DocIdSeq", sequenceName = "DOC_ID_SEQ", allocationSize = 1) 
    private Long docId; 

    @Transient 
    private Set<Section> sections = new HashSet<Section>(0); 

    @PostPersist 
    public void updateChildIds() { 
     for (Section section : this.sections) { 
      section.getId().setDocId(this.docId); 
     } 
    } 
} 

당신이 볼 수 있듯이을, 섹션 관계는 JPA 그것을 관리하지 않습니다 의미, 지금은 과도하다. Document를 영속화 한 후에 프레임 워크는 updateChildIds 함수를 호출합니다.이 함수는 섹션 ID를 새로 유지 된 Document ID로 수동으로 업데이트합니다.

은 다음과 외관에서 설명 될 수있다 :

@Stateless 
public void DocumentFacade implements DocumentFacadeLocal { 

    @PersistenceContext 
    private EntityManager entityManager; 

    public void save(Document entity) throws Exception { 
     this.entityManager.persist(entity); 
     this.entityManager.flush(); 
     this.persistTransientEntities(entity); 
     this.entityManager.flush(); 
    } 

    private void persistTransientEntities(CaseInstructionSheet entity) { 
     for (Section section : entity.getSections()) { 
      this.entityManager.persist(section); 
     } 
    } 
} 
0

사실, JPA는 완벽하게이 문제를 처리 할 수 ​​있습니다. 찾고있는 특수 효과는 MapsId입니다. (가) docId 당신은 단순히 다음과 같은 추가 할 필요에 Section에 경우

, :

@MapsId("docId") 

MapsId 주석의 값이 복합 기본 키의 속성 이름 (이 경우에 어떤 같음)

+0

내 경우에 @MapsId가 유용 할 것이라고 생각합니까? https://stackoverflow.com/questions/46159867/ 원래 포스터의 주요 차이점은 ManyToOne 대신 OneToOne을 사용한다는 점입니다. – gouessej