JPA - Mengembalikan id yang dibuat secara otomatis setelah persist ()

113

Saya menggunakan JPA (EclipseLink) dan Spring. Katakanlah saya memiliki entitas sederhana dengan ID yang dibuat secara otomatis:

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

     // ...
}

Di kelas DAO saya, saya memiliki metode sisipkan yang memanggil persist()entitas ini. Saya ingin metode mengembalikan ID yang dihasilkan untuk entitas baru, tetapi ketika saya mengujinya, ia mengembalikannya 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; // ???
    }
}

Saya juga memiliki kelas layanan yang membungkus DAO, jika itu membuat perbedaan:

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

    public int addNewABC(ABC abc) {
         return abcDao.insertABC(abc);
    }
}
sura2k
sumber
Yang serupa, dapat merujuk stackoverflow.com/q/3328813/366964
Nayan Wadekar
Terima kasih atas jawabannya. Dan sebagai solusi yang rumit (bukan JPA) kita dapat menggunakan id unik lain seperti stempel waktu unix.
surah2k
1
kemungkinan duplikat Kapan JPA menyetel @GeneratedValue @Id
Raedwald

Jawaban:

184

ID hanya dijamin akan dibuat pada waktu yang ditentukan. Mempertahankan entitas hanya membuatnya "melekat" pada konteks ketekunan. Jadi, hapus pengelola entitas secara eksplisit:

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

atau kembalikan entitas itu sendiri, bukan ID-nya. Ketika transaksi berakhir, flush akan terjadi, dan pengguna entitas di luar transaksi akan melihat ID yang dihasilkan di entitas tersebut.

@Override
public ABC addNewABC(ABC abc) {
    abcDao.insertABC(abc);
    return abc;
}
JB Nizet
sumber
10
NB: ini perlu menganotasi bidang id dengan @GeneratedValue- apa pun yang diperlukan
Mr_and_Mrs_D
Bisakah Anda menjelaskan masalah dalam mencoba mencapai ini dengan id komposit stackoverflow.com/questions/31362100/…
bl3e
Apakah ada hukuman kinerja (atau efek negatif lainnya) dari pembilasan secara manual setelah bertahan?
Craig Otis
3
Ya, ada: perjalanan bolak-balik yang tidak perlu ke database jika transaksi akhirnya dibatalkan, kemungkinan pengecualian jika entitas yang ada (atau entitas yang dihapus lainnya) belum dalam keadaan yang valid. Urutan atau generator uuid lebih sederhana dan lebih efisien, dan tidak memiliki masalah ini karena ID dibuat dan ditetapkan sebelum entitas ditulis ke database.
JB Nizet
1
@JBNizet, apakah Anda perlu mengembalikan instance atau referensi yang diteruskan masih valid? Maksud saya, apakah insertABCmembuat objek baru? Atau modifikasi yang lama?
ryvantage
13
@Entity
public class ABC implements Serializable {
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     private int id;   
}

periksa apakah notasi @GeneratedValue ada di kelas entitas Anda. Ini memberi tahu JPA tentang perilaku yang dibuat secara otomatis pada properti entitas Anda

utkal patel
sumber
4

Beginilah cara saya melakukannya:

EntityManager entityManager = getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(object);
transaction.commit();
long id = object.getId();
entityManager.close();
Koray Tugay
sumber
Ini tidak berfungsi memberikan nol sebagai Pengembalian setelah menyimpan data ke dalam tabel. baik penyegaran tidak berfungsi pada kasus ini .. Apa yang harus saya lakukan untuk ini. tolong sarankan cara ... Terima kasih
Vikrant Kashyap
1
@VikrantKashyap Silakan posting pertanyaan baru dengan kode kecil dan sebutkan saya sehingga saya dapat melihatnya.
Koray Tugay
2

Anda juga bisa menggunakan GenerationType.TABLE sebagai ganti IDENTITY yang hanya tersedia setelah penyisipan.

James
sumber
2
Hanya kata-kata peringatan. Ketika saya mencoba GenerationType.TABLE, itu membuat tabel terpisah bernama hibernate_sequences dan memulai ulang urutan dari 1.
SriSri
0

Pilihan lain yang kompatibel dengan 4.0:

Sebelum melakukan perubahan, Anda dapat memulihkan CayenneDataObjectobjek baru dari koleksi yang terkait dengan konteks, seperti ini:

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

lalu akses ObjectIduntuk masing-masing dalam koleksi, seperti:

ObjectId objectId = dataObject.getObjectId();

Akhirnya Anda dapat mengulang di bawah nilai, di mana biasanya id yang dihasilkan akan menjadi yang pertama dari nilai (untuk kunci kolom tunggal) di Peta yang dikembalikan oleh getIdSnapshot(), itu berisi juga nama kolom yang terkait dengan PK sebagai kunci:

objectId.getIdSnapshot().values()
emecas
sumber
0

Beginilah cara saya melakukannya. Anda dapat mencoba

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

    public int addNewABC(ABC abc) {
         ABC.setId(0);
         return abcDao.insertABC(abc);
    }
}
Anh Khoa
sumber
-3
em.persist(abc);
em.refresh(abc);
return abc;
Andrey
sumber
Metode ini tidak berhasil untuk saya. Mendapat kesalahan ini: javax.persistence.PersistenceException: org.hibernate.HibernateException: instance ini belum ada sebagai baris dalam database]
rtcarlson
@ Artcarlson, ya ini tidak akan berhasil. jika Anda membuat objek baru, yang Anda butuhkan em.flush()bukanlah em.refresh(abc).
Ibrahim Dauda