JPA - Kaldıktan sonra otomatik olarak oluşturulmuş bir kimliği döndürme ()


113

JPA (EclipseLink) ve Spring kullanıyorum. Otomatik oluşturulan bir kimliğe sahip basit bir varlığım olduğunu varsayalım:

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

     // ...
}

DAO sınıfımda, persist()bu varlığı çağıran bir ekleme yöntemim var . Yöntemin yeni varlık için oluşturulan kimliği döndürmesini istiyorum, ancak onu test ettiğimde 0bunun yerine geri dönüyor .

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

Ayrıca, bir fark yaratıyorsa, DAO'yu saran bir hizmet sınıfım var:

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

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


Cevaplar için teşekkürler. Zor bir çözüm olarak (JPA değil), unix zaman damgası gibi başka bir benzersiz kimlik kullanabiliriz.
sura2k

Yanıtlar:


184

Kimliğin yalnızca yıkama zamanında üretilmesi garanti edilir. Bir varlığı sürdürmek, onu yalnızca kalıcılık bağlamına "bağlı" kılar. Dolayısıyla, varlık yöneticisini açık bir şekilde temizleyin:

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

veya kimliği yerine varlığın kendisini döndürür. İşlem sona erdiğinde, temizleme gerçekleşir ve işlemin dışındaki varlığın kullanıcıları böylece varlıkta oluşturulan kimliği görür.

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

10
NB: bunun id alanını @GeneratedValue- ne gerektiriyorsa
Mr_and_Mrs_D

Bunu gerçekleştirmeye çalışırken karşılaştığınız sorunları açıklayabilir misiniz? Bileşik id stackoverflow.com/questions/31362100/…
bl3e

Israr ettikten sonra elle yıkamanın bir performans cezası (veya başka olumsuz etkileri) var mı?
Craig Otis

3
Evet, var: işlem geri alınırsa veritabanına gereksiz gidiş dönüş, kalıcı varlık (veya diğer temizlenmiş varlıklar) henüz geçerli durumda değilse olası istisnalar. Bir dizi veya uuid oluşturucu daha basit ve daha verimlidir ve bu sorunları yaşamaz çünkü kimlik, varlık veritabanına yazılmadan önce oluşturulur ve atanır.
JB Nizet

1
@JBNizet, örneği iade etmeniz gerekiyor mu yoksa aktarılan referans hala geçerli mi? Demek istediğim, insertABCyeni bir obje yaratır mı? Veya eskisini değiştirmek mi?
ryvantage

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

@GeneratedValue gösteriminin varlık sınıfınızda olduğunu kontrol edin Bu, JPA'ya otomatik olarak oluşturulan varlık mülkünüz hakkında bilgi verir


4

Ben böyle yaptım:

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

Verileri tabloya koyduktan sonra dönüş olarak sıfır vererek çalışmıyor. bu durumda yenileme çalışmıyor .. Bunun için ne yapmalıyım. lütfen bir yol önerin ... Teşekkürler
Vikrant Kashyap

1
@VikrantKashyap Lütfen küçük bir kodla yeni bir soru gönderin ve benden bahsedin ki bir bakayım.
Koray Tugay

2

Yalnızca eklemeden sonra kullanılabilen IDENTITY yerine GenerationType.TABLE da kullanabilirsiniz.


2
Sadece bir uyarı sözü. GenerationType.TABLE'ı denediğimde, hibernate_sequences adında ayrı bir tablo oluşturdu ve diziyi 1'den yeniden başlattı.
SriSri

0

4.0 ile uyumlu başka bir seçenek:

Değişiklikleri uygulamadan önce, yeni CayenneDataObjectnesneleri bağlamla ilişkilendirilmiş koleksiyondan şu şekilde kurtarabilirsiniz :

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

daha sonra ObjectIdkoleksiyondaki her biri için şu şekilde erişin :

ObjectId objectId = dataObject.getObjectId();

Son olarak, değerlerin altında yineleme yapabilirsiniz, burada genellikle oluşturulan-id, tarafından döndürülen Harita'daki değerlerden (tek bir sütun anahtarı için) ilk getIdSnapshot()olacaktır, ayrıca PK ile ilişkili sütun ad (lar) ını da içerir. anahtar (lar) olarak:

objectId.getIdSnapshot().values()

0

Ben böyle yaptım. Deneyebilirsin

    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;

Bu yöntem benim için işe yaramadı. Bu hatayı aldım: javax.persistence.PersistenceException: org.hibernate.HibernateException: bu örnek henüz veritabanında bir satır olarak mevcut değil]
rtcarlson

@rtcarlson, evet bu işe yaramayacak. yeni bir nesne yaratıyorsanız ihtiyacınız olan şey em.flush()değildir em.refresh(abc).
Ibrahim Dauda
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.