문제

나는 그 아래에 최대 절전 모드와 함께 JPA를 사용하고 있으며, 일을 합병하는 데 어려움을 겪고 있지만, JPA와 관련된 문제를 설명하기 전에, 내 문제가 내 접근 방식에서 비롯된 경우를 대비하여 내가 달성하려는 것을 배치하겠습니다. .

다른 시스템에 배치 해야하는 시스템의 데이터가 있습니다. 이를 위해 데이터를 읽은 다음 해당 데이터를 기반으로 새 ORM 객체를 구성하는 경우 ORM 객체를 데이터베이스에 지속하려고합니다. 이제 데이터베이스가 비어 있으면 프로그램은 간단한 EM.Persist (Object) 호출로 문제없이 작동합니다. 그러나 데이터베이스에 데이터가있는 경우이 프로세스를 실행할 수 있고, 새 데이터를 추가하고 필요한 경우 이전 데이터를 업데이트 할 수 있습니다. 이것이 제가 문제가있는 곳입니다.

항목이 데이터베이스에 이미 존재하는지 확인하기 위해 간단한 점검을 수행합니다. 아무것도 발견되지 않으면 기록이 존재하면 병합을 시도합니다. 중복 레코드 오류로 실패합니다.

ERROR JDBCExceptionReporter - Violation of UNIQUE KEY constraint 'UK-SubStuff-StuffId-SubStuffNumber'. Cannot insert duplicate key in object 'SubStuff'.

em.merge () 호출이 업데이트 대신 삽입을 시도하는 것이 이상하게 저를 놀라게합니다 (SQL 로깅을 통해 이것을 확인했습니다).

Hibernate: insert into SubStuff (SubStuffNumber, StuffId, Name, TypeId) values (?, ?, ?, ?)

나는 서브 객체로 캐스케이드하는 객체를 사용하고 있음에 주목해야합니다. 하위 객체에서 실패가 발생하고 있으며, 이는 하위 객체를 먼저 시도하고 병합 할 것으로 예상하기 때문에 나에게 의미가 있습니다.

아래는 내 코드입니다. 거친 상태를 변명하십시오. 여기에 몇 가지 해결 방법을 문서화하려고했습니다.

private void storeData(Collection<Stuff> Stuffs) {

    for (Stuff stuff : Stuffs) {
        //I think this first block can be safely ignored, as I am having no issues with it
        //  Left it in just in case someone more experianced then I sees the root of the issue here.
        Collection<SubStuff> subStuffs = stuff.getSubStuffCollection();
        for (SubStuff s : subStuffs) {
            //Persist SubStuff Type, which DOES NOT cascade,
            //  due to it not having an internal SubStuff collection
            Query q = em.createNamedQuery("SubStuffType.findByType");
            q.setParameter("type", f.getTypeId().getType());
            try {
                SubStuffType sst = (SubStuffType) q.getSingleResult();
                s.setTypeId(sst);
            } catch (NoResultException ex) {
                if (logger.isDebugEnabled()) logger.debug("SubStuff Type not found, persisting");
                em.persist(s.getTypeId());
            }
        }

        if (em.find(Stuff.class, stuff.getId()) == null) {
            //Persist on Stuffs will cascade to SubStuffs
            em.persist(stuff);
        } else {
            //  Failing to merge SubStuff, tries to insert duplicate
            //  Merge SubStuff first
            // The block below is my attempt to merge the SubStuff Collection before merging Stuff,
            //  it creates the same isuse as a straight merge of Stuff.
            Collection<SubStuff> mergedSubStuffs = new ArrayList<SubStuff>(SubStuffs.size());
            for (SubStuff s : SubStuffs) {
                Query q = em.createNamedQuery("SubStuff.findBySubStuffNumberStuffId");
                q.setParameter("SubStuffNumber", s.getSubStuffNumber());
                q.setParameter("StuffId", stuff.getId());
                try {
                    SubStuff subStuff = (SubStuff) q.getSingleResult();
        // -----> Merge fails, with an duplicate insert error
                    SubStuff mergedSubStuff = em.merge(s);
                    mergedSubStuffs.add(mergedSubStuff);
                } catch (NoResultException ex) {
                    throw ex;
                }
            }
            stuff.setSubStuffCollection(mergedSubStuffs);

        // -----> This will fails with same error as above, if I remove the attempt
            //  to merge the sub objects
            em.merge(stuff);
        }
    }
}

JPA 경험을 가진 사람이 나를 도울 수 있다면 정말 감사하겠습니다. Hibernate의 SaveorupDate ()와 JPA의 Merge ()의 차이는 분명히 나를 넘어가고 있지만 Enitymanger의 병합에 대한 여러 기사를 읽었음에도 불구하고 여전히 여기서 일어나는 일을 둘러 볼 수는 없습니다.

시간 내 줘서 고마워.

도움이 되었습니까?

해결책

Stackoverflow의 저주가 다시 쳤다. 약 하루 동안이 문제를 해결 한 후이 질문을 게시하기로 결정했습니다. 20 분 안에 유레카 순간이 있었고 해결했습니다. 부분적으로 나는 질문을 게시 할만 큼 충분히 내 생각을 명확히했기 때문입니다. 어떤 정보가 질문과 관련이 있는지에 대해 생각하면서 나는 자동 생성 된 키가 비난을 받는다는 것을 깨달았습니다 (또는 올바르게, 어리석은 처리가 합병에 대한 어리석은 처리).

내 문제는 사무리 (최악의 대체 명명 체계, 죄송합니다)에 자율적 인 인공 기본 키가 있다는 것입니다. 그래서 병합 할 때 나는해야했다.

SubStuff subStuff = (SubStuff) q.getSingleResult();
//++++++++
s.setId(subStuff.getId());
//++++++++

//The following code can be removed.
//--- SubStuff mergedSubStuff = em.merge(f);
//--- mergedSubStuffs.add(mergedSubStuff);

이것은 이미 데이터베이스에 이미 존재하는 행의 주요 키를 설정하고 초기 테스트시 잘 작동하는 것 같습니다.

병합 호출은 em.merge (stuff)에 대한 호출로 단순화 될 수 있으며, 이는 더 이상 해당 루프 내부에서 병합을 수행하지 않기 때문에 병합 징수 컬렉션을 모두 함께 제거 할 수 있습니다.

말도 안되는 긴 질문을 읽은 사람 덕분에 내 질문이 미래의 누군가에게 유용하기를 바랍니다.

다른 팁

귀하의 문제는 다음 몇 줄에 문제가 있습니다.

Collection<SubStuff> mergedSubStuffs = new ArrayList<SubStuff>(SubStuffs.size());
...
stuff.setSubStuffCollection(mergedSubStuffs);

JPA는 새로운 컬렉션을 완전한 새로운 하위 엔티티 세트로 간주 할 것이며 항상이를 삽입 할 것입니다. 재료 엔터티 내에서 원래의 사무실 모음으로 계속 작업하면 괜찮을 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top