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);
    }
}


Terima kasih atas jawabannya. Dan sebagai solusi yang rumit (bukan JPA) kita dapat menggunakan id unik lain seperti stempel waktu unix.
surah2k

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;
}

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


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();

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.


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()

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);
    }
}

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

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.