복붙노트

[SPRING] 일대 다 관계를 지속 할 때 제약 조건 위반

SPRING

일대 다 관계를 지속 할 때 제약 조건 위반

최대 절전 모드와 MySQL을 사용하는 스프링 MVC 응용 프로그램에서 다음과 같은 제약 조건 위반 예외가 발생합니다.

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:  
Cannot add or update a child row: a foreign key constraint fails  
(`mybd`.`hl7_documententity`, CONSTRAINT `hl7_documententity_ibfk_1`   
FOREIGN KEY (`ptcode`, `ptcodesystem`)    
REFERENCES `hl7_generalcode` (`code`, `codesystem`))

이 문제는 아래에 정의 된 GeneralCode 유형의 속성이 포함 된 DocumentEntity를 저장하려고 할 때 발생합니다.

나는이 오류에 대한 많은 게시물과 블로그를 읽었지만 아무도 내 문제를 해결하지 못하는 것 같습니다. 이 오류를 어떻게 해결할 수 있습니까?

다음은 DocumentEntity 클래스입니다.

@Entity
@Table(name = "hl7_documententity")
public class HL7DocumentEntity extends BaseEntity{

    //other properties

    @ManyToOne
    @JoinColumns({ @JoinColumn(name = "ptcode", referencedColumnName = "code"),
        @JoinColumn(name = "ptcodesystem", referencedColumnName = "codesystem")
    })
    private HL7GeneralCode providertype;

    //getters and setters    
}

다음은 GeneralCode 클래스입니다.

@Entity
@Table(name = "hl7_generalcodes")
public class HL7GeneralCode implements Serializable{

    private static final long serialVersionUID = -8620565054475096516L;

    @EmbeddedId
    private HL7EmbedCodePK codePk;

    @OneToMany(mappedBy = "providertype")
    private Set<HL7DocumentEntity> documententities;

    ////////////getters and setters    
}

컨트롤러의 코드는 다음과 같습니다.

HL7GeneralCode authcode = processGeneralCode(grandkid);
HL7GeneralCode testcode = this.clinicService.findGeneralCodeByPK(authcode.getCodePk().getCode(), authcode.getCodePk().getCodesystem());
if(testcode==null){
    authcode.addDocumententity(mydent);
    this.clinicService.savehl7GeneralCode(authcode);
    mydent.setProvidertype(authcode);
    //this next line throws the error
    this.clinicService.savehl7DocumentEntity(mydent);
}else{
    //other stuff
}

다음은 DA 방법입니다.

@Repository
public class JpaSomethingRepositoryImpl implements SomethingRepository {

    @PersistenceContext
    private EntityManager em;

    @Override
    @Transactional
    public void savehl7DocumentEntity(HL7DocumentEntity de) {
        HL7GeneralCode code = de.getProvidertype();
        if(code !=null && code.getCodePk()==null){//HL7GeneralCode is not persistent. We don't support that
            throw new IllegalStateException("Cannot persist an adress using a non persistent HL7GeneralCode");
        }
        System.out.println("=========================== inside jpaCdaRespository.saveDocEntity(de)");
        de.setProvidertype(null);
        if(code.getDocumententities()!=null){
            ArrayList<HL7DocumentEntity> addrList = new ArrayList<HL7DocumentEntity>();
            addrList.addAll(code.getDocumententities());
            addrList.remove(de);
            Set<HL7DocumentEntity> myaddrs = new HashSet<HL7DocumentEntity>(addrList);
            code.setDocumententities(myaddrs);
        }
        code = em.merge(code); 
        de.setProvidertype(code);
        code.addDocumententity(de);

        if (de.getId() == null) {
            System.out.println("[[[[[[[[[[[[ about to persist de ]]]]]]]]]]]]]]]]]]]]");
            em.persist(de);
        } else {
            System.out.println("]]]]]]]]]]]]]]]]]] about to merge de [[[[[[[[[[[[[[[[[[[[[");
            de = em.merge(de);
        }
    }
}

실행 된 SQL 문과 절전 모드에서 SQL을 통해 삽입하려고 시도하는 실제 값은 다음과 같습니다.

[[[[[[[[[[[[ about to persist de ]]]]]]]]]]]]]]]]]]]]
DEBUG SQL - insert into hl7_documententity (author_id, authpar_id, entitytype, id_extension, id_root, ptcode, ptcodesystem, id) values (?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into hl7_documententity (author_id, authpar_id, entitytype, id_extension, id_root, ptcode, ptcodesystem, id) values (?, ?, ?, ?, ?, ?, ?, ?)
TRACE BasicBinder - binding parameter [1] as [INTEGER] - <null>
TRACE BasicBinder - binding parameter [2] as [INTEGER] - <null>
TRACE BasicBinder - binding parameter [3] as [VARCHAR] - <null>
TRACE BasicBinder - binding parameter [4] as [VARCHAR] - NI
TRACE BasicBinder - binding parameter [5] as [VARCHAR] - nullFlavor
TRACE BasicBinder - binding parameter [6] as [VARCHAR] - UNK
TRACE BasicBinder - binding parameter [7] as [VARCHAR] - HL7NullFlavor
TRACE BasicBinder - binding parameter [8] as [INTEGER] - 32787
WARN  SqlExceptionHelper - SQL Error: 1452, SQLState: 23000
ERROR SqlExceptionHelper - Cannot add or update a child row: a foreign key constraint fails (`docbd`.`hl7_documententity`, CONSTRAINT `hl7_documententity_ibfk_1` FOREIGN KEY (`ptcode`, `ptcodesystem`) REFERENCES `hl7_generalcode` (`code`, `codesystem`))
INFO  AbstractBatchImpl - HHH000010: On release of batch it still contained JDBC statements
WARN  warn - Handler execution resulted in exception

이 링크를 클릭하면 EmbedCodePK 클래스 코드를 읽을 수 있습니다. 이 링크를 클릭하면 전체 스택 추적을 읽을 수 있습니다. 다음은 BaseEntity 클래스의 코드에 대한 링크입니다.

해결법

  1. ==============================

    1.변경 :

    변경 :

    @OneToMany(mappedBy = "providertype")
    private Set<HL7DocumentEntity> documententities;
    

    이에:

    @OneToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "Link_Documents", joinColumns = {@JoinColumn(name = "codePk", unique = true)}, inverseJoinColumns = {@JoinColumn(name = "change_this_with_primary_key_variable_name_from_HL7DocumentEntity")})
     private Set<HL7DocumentEntity> documententities;
    

    그리고 HL7DocumentEntity에서 다음과 같이 변경됩니다.

    @ManyToOne
        @JoinColumns({ @JoinColumn(name = "ptcode", referencedColumnName = "code"),
            @JoinColumn(name = "ptcodesystem", referencedColumnName = "codesystem")
        })
        private HL7GeneralCode providertype;
    

    다음으로 변경하십시오.

    @ManyToOne(fetch = FetchType.LAZY)
      @JoinTable(name = "Link_Documents", joinColumns = {@JoinColumn(name = "change_this_with_primary_key_variable_name_from_HL7DocumentEntity")}, inverseJoinColumns = {@JoinColumn(name = "codePk")})
      private HL7GeneralCode providertype;
    

    "Change_this_prime_key_variable_name_from_HL7DocumentEntity"를 BaseEntity에있는 것처럼 "id"로 변경해야하지만 sql 테이블을 살펴보아야 올바른 이름을 알 수 있습니다.

    내가 알기를 바랍니다. JPA에게 2 개의 테이블을 연결하는 데 동일한 "Link_Documents"테이블을 사용하도록 지시하는 방법. 나는 이것이 당신의 실수라고 생각합니다. 올바른 변수 이름으로 말한 부분을 변경해야하며 작동해야한다고 생각합니다.

  2. ==============================

    2.내가이 코드를 정리하면 시작할 것입니다.

    내가이 코드를 정리하면 시작할 것입니다.

    최대 절전 모드 문서에서는 필드 변수에 주석을 추가하는 것이 좋다고 말할 수도 있지만, 표준으로서의 나쁜 생각입니다. 필드 레벨은 lazy fetches의 경우 필드가 액세스 될 수 있기 전에 최대 절전 모드에서 프록시를 생성 할 것을 요구합니다. 그래서 그것을 올바르게하는 데 익숙해지면 문제를 발견하는 불행을 겪지 않을 것입니다. 프로퍼티 레벨 액세스가 프록시를 필요로하지 않으므로 모든 주석을 getter로 이동하십시오.

    필드 수준 변수는 비공개이어야합니다.

    당신은 Integer를 Integer로 캐스팅하고 있습니다. 그 중 일부는 저를 보지 않으려 고하며, 사실상 당신의 문제가되는 게으름의 바보 일 것입니다.

    그 동안 새로운 HashSet (0)으로 세트를 초기화하십시오; 그런 것들. 아직도 우리를 업데이 트 고장.

  3. from https://stackoverflow.com/questions/25454703/constraint-violation-when-persisting-one-to-many-relation by cc-by-sa and MIT license