JPA-persist () 후 자동 생성 된 ID 반환


113

JPA (EclipseLink)와 Spring을 사용하고 있습니다. 자동 생성 된 ID가있는 간단한 엔터티가 있다고 가정 해 보겠습니다.

@Entity
public class ABC implements Serializable {
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     private int id;

     // ...
}

내 DAO 클래스에는 persist()이 엔터티 를 호출하는 삽입 메서드가 있습니다. 메서드가 새 엔터티에 대해 생성 된 ID를 반환하기를 원하지만 테스트 할 때 0대신 반환 됩니다.

public class ABCDao {
    @PersistenceContext
    EntityManager em;

    @Transactional(readOnly=false)
    public int insertABC(ABC abc) {
         em.persist(abc);
         // I WANT TO RETURN THE AUTO-GENERATED ID OF abc
         // HOW CAN I DO IT?
         return abc.id; // ???
    }
}

차이가 나는 경우 DAO를 래핑하는 서비스 클래스도 있습니다.

public class ABCService {
    @Resource(name="ABCDao")
    ABCDao abcDao;

    public int addNewABC(ABC abc) {
         return abcDao.insertABC(abc);
    }
}

유사 하나, 참조 할 수 있습니다 stackoverflow.com/q/3328813/366964
Nayan Wadekar

답변 해 주셔서 감사합니다. 그리고 까다로운 솔루션 (JPA가 아님)으로 유닉스 타임 스탬프와 같은 다른 고유 ID를 사용할 수 있습니다.
sura2k

답변:


184

ID는 플러시 시간에만 생성됩니다. 엔티티를 지속하면 지속성 컨텍스트에만 "연결"됩니다. 따라서 엔티티 관리자를 명시 적으로 비우십시오.

em.persist(abc);
em.flush();
return abc.getId();

또는 ID가 아닌 항목 자체를 반환합니다. 트랜잭션이 종료되면 플러시가 발생하고 트랜잭션 외부의 엔티티 사용자는 엔티티에서 생성 된 ID를 볼 수 있습니다.

@Override
public ABC addNewABC(ABC abc) {
    abcDao.insertABC(abc);
    return abc;
}

10
NB : 이것은 id 필드에 주석을 달아야합니다 @GeneratedValue.-무엇이 수반
되든


지속 후 수동으로 플러시하면 성능 저하 (또는 기타 부정적인 영향)가 있습니까?
Craig Otis

3
예, 트랜잭션이 롤백되는 경우 불필요한 데이터베이스 왕복, 지속 된 엔터티 (또는 다른 플러시 된 엔터티)가 아직 유효한 상태가 아닌 경우 잠재적 인 예외가 있습니다. 시퀀스 또는 uuid 생성기는 더 간단하고 효율적이며 엔티티가 데이터베이스에 기록되기 전에 ID가 생성되고 할당되기 때문에 이러한 문제가 없습니다.
JB Nizet 2016

1
@JBNizet, 인스턴스를 반환해야합니까 아니면 전달 된 참조가 여전히 유효합니까? 내 말은, insertABC새로운 객체를 생성합니까? 아니면 이전 버전을 수정 하시겠습니까?
ryvantage 2016 년

13
@Entity
public class ABC implements Serializable {
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     private int id;   
}

엔티티 클래스에 @GeneratedValue 표기법이 있는지 확인하십시오. 이는 엔티티 속성 자동 생성 동작에 대해 JPA에 알려줍니다.


4

이것이 내가 한 방법입니다.

EntityManager entityManager = getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(object);
transaction.commit();
long id = object.getId();
entityManager.close();

데이터를 테이블에 유지 한 후 반환 값으로 0을 제공하지 않습니다. 이 경우 새로 고침이 작동하지 않습니다 .. 어떻게해야합니까? 방법을 제안 해주십시오 감사합니다 ...
Vikrant 쉬얍

1
@VikrantKashyap 작은 코드로 새 질문을 게시하고 제가 살펴볼 수 있도록 저를 언급하십시오.
Koray Tugay

2

삽입 후에 만 ​​사용할 수있는 IDENTITY 대신 GenerationType.TABLE을 사용할 수도 있습니다.


2
주의의 한마디. GenerationType.TABLE을 시도했을 때 hibernate_sequences라는 별도의 테이블을 만들고 1부터 시퀀스를 다시 시작했습니다.
SriSri

0

4.0과 호환되는 또 다른 옵션 :

변경 사항을 커밋하기 전에 CayenneDataObject다음과 같이 컨텍스트와 연결된 컬렉션에서 새 객체를 복구 할 수 있습니다 .

CayenneDataObject dataObjectsCollection = (CayenneDataObject)cayenneContext.newObjects();

그런 다음 다음 ObjectId과 같이 컬렉션의 각 항목에 액세스합니다 .

ObjectId objectId = dataObject.getObjectId();

마지막으로 값 아래에서 반복 할 수 있습니다. 일반적으로 생성 된 ID는에서 반환 한 맵의 값 (단일 열 키의 경우) 중 첫 번째 값이됩니다 getIdSnapshot(). 여기에는 PK와 관련된 열 이름도 포함됩니다. 키로 :

objectId.getIdSnapshot().values()

0

이것이 내가 한 방법입니다. 당신은 시도 할 수 있습니다

    public class ABCService {
    @Resource(name="ABCDao")
    ABCDao abcDao;

    public int addNewABC(ABC abc) {
         ABC.setId(0);
         return abcDao.insertABC(abc);
    }
}

-3
em.persist(abc);
em.refresh(abc);
return abc;

이 방법은 저에게 효과적이지 않았습니다. 이 오류가 발생했습니다 : javax.persistence.PersistenceException : org.hibernate.HibernateException :이 인스턴스는 아직 데이터베이스에 행으로 존재하지 않습니다.]
rtcarlson

@rtcarlson, 네, 작동하지 않습니다. 새 개체를 만드는 경우 필요한 것은 em.flush()아닙니다 em.refresh(abc).
Ibrahim Dauda 2015
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.