जेपीए - लगातार होने के बाद एक ऑटो जनित आईडी वापस करना


113

मैं जेपीए (एक्लिप्सलिंक) और स्प्रिंग का उपयोग कर रहा हूं। कहो कि मेरे पास एक ऑटो-जनरेटेड आईडी के साथ एक साधारण इकाई है:

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

     // ...
}

मेरे DAO वर्ग में, मेरे पास एक आवेषण विधि है जो persist()इस इकाई पर कॉल करती है। मैं नई इकाई के लिए जनरेट की गई आईडी को वापस करने की विधि चाहता हूं, लेकिन जब मैं इसका परीक्षण करता हूं, तो यह 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; // ???
    }
}

मेरे पास एक सेवा वर्ग है जो डीएओ को लपेटता है, अगर इससे कोई फर्क पड़ता है:

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

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


जवाब के लिए धन्यवाद। और एक मुश्किल समाधान (एक जेपीए नहीं) के रूप में हम यूनिक्स टाइमस्टैम्प जैसी एक और अनोखी आईडी का उपयोग कर सकते हैं।
sura2k

1
के संभावित डुप्लिकेट जब जेपीए एक @GeneratedValue @Id सेट करता है
Raedwald

जवाबों:


184

आईडी केवल फ्लश समय पर उत्पन्न होने की गारंटी है। एक इकाई का निर्माण केवल इसे दृढ़ता के संदर्भ में "संलग्न" बनाता है। इसलिए, या तो इकाई प्रबंधक को स्पष्ट रूप से प्रवाहित करें:

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

या अपनी आईडी के बजाय संस्था को ही लौटाएं। जब लेनदेन समाप्त होता है, तो फ्लश होगा, और लेनदेन के बाहर इकाई के उपयोगकर्ता इस प्रकार इकाई में उत्पन्न आईडी देखेंगे।

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

10
नायब: इसके लिए आईडी फील्ड को @GeneratedValue
एनोटेट करने की

क्या आप समग्र आईडी stackoverflow.com/questions/31362100/…
bl3e

क्या प्रदर्शन पर जुर्माना (या कोई अन्य नकारात्मक प्रभाव) मैन्युअल रूप से जारी रखने के बाद निस्तब्धता है?
क्रेग ओटिस

3
हाँ, वहाँ है: डेटाबेस के लिए अनावश्यक राउंडट्रिप यदि लेन-देन को रोलबैक किया जा रहा है, तो संभावित अपवाद यदि स्थायी इकाई (या अन्य प्लावित निकाय) अभी तक वैध स्थिति में नहीं है। एक अनुक्रम या uuid जनरेटर सरल और अधिक कुशल है, और इन समस्याओं के कारण नहीं है क्योंकि आईडी डेटाबेस को लिखे जाने से पहले आईडी उत्पन्न और असाइन किया गया है।
जेबी निज़ेट

1
@JBNizet, क्या आपको उदाहरण वापस करने की आवश्यकता है या पारित संदर्भ अभी भी वैध है? मेरा मतलब है, insertABCएक नई वस्तु बनाता है? या पुराने को संशोधित करें?
रवांटेज

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

तालिका में डेटा को जारी रखने के बाद रिटर्न के रूप में शून्य देने का काम नहीं कर रहा है। या तो इस मामले में ताज़ा काम नहीं कर रहा है .. मुझे इसके लिए क्या करना चाहिए। कृपया एक तरीका
सुझाएं

1
@VikrantKashyap कृपया छोटे कोड के साथ एक नया प्रश्न पोस्ट करें और मेरा उल्लेख करें ताकि मैं देख सकूं।
कोरे तुगे

2

आप IDENTITY के बजाय GenerationType.TABLE का भी उपयोग कर सकते हैं जो केवल डालने के बाद उपलब्ध है।


2
सिर्फ चेतावनी का एक शब्द। जब मैंने GenerationType.TABLE की कोशिश की, तो इसने हाइबरनेट_ परिणाम के नाम से एक अलग तालिका बनाई और अनुक्रम को 1 से फिर से शुरू किया
श्रीस्री

0

4.0 के लिए एक और विकल्प:

परिवर्तनों को करने से पहले, आप CayenneDataObjectसंदर्भ से संबंधित संग्रह से नई वस्तु (ओं) को पुनर्प्राप्त कर सकते हैं , जैसे:

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

फिर ObjectIdसंग्रह में प्रत्येक के लिए उपयोग करें , जैसे:

ObjectId objectId = dataObject.getObjectId();

अंत में आप उन मानों के अंतर्गत पुनरावृत्ति कर सकते हैं, जहाँ आमतौर पर जेनरेट-ईडी द्वारा लौटाए गए मानचित्र में मानों में से पहला मान (एकल स्तंभ कुंजी के लिए) होने वाला getIdSnapshot()होता है , इसमें पीके से संबंधित कॉलम नाम (s) भी होता है। कुंजी के रूप में:

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)
इब्राहिम दौड़ा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.