हाइबरनेट जेपीए अनुक्रम (गैर-आईडी)


138

क्या कुछ कॉलम के लिए DB अनुक्रम का उपयोग करना संभव है जो पहचानकर्ता नहीं है / एक समग्र पहचानकर्ता का हिस्सा नहीं है ?

मैं hibernate का उपयोग jpa प्रदाता के रूप में कर रहा हूं, और मेरे पास एक तालिका है जिसमें कुछ कॉलम हैं जो मान उत्पन्न करते हैं (एक अनुक्रम का उपयोग करके), हालांकि वे पहचानकर्ता का हिस्सा नहीं हैं।

मैं एक इकाई के लिए एक नया मान बनाने के लिए एक अनुक्रम का उपयोग करना चाहता हूं, जहां अनुक्रम के लिए स्तंभ प्राथमिक भाग का नहीं (का हिस्सा है):

@Entity
@Table(name = "MyTable")
public class MyEntity {

    //...
    @Id //... etc
    public Long getId() {
        return id;
    }

   //note NO @Id here! but this doesn't work...
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "myGen")
    @SequenceGenerator(name = "myGen", sequenceName = "MY_SEQUENCE")
    @Column(name = "SEQ_VAL", unique = false, nullable = false, insertable = true, updatable = true)
    public Long getMySequencedValue(){
      return myVal;
    }

}

फिर जब मैं ऐसा करता हूं:

em.persist(new MyEntity());

आईडी जनरेट होगी, लेकिन mySequenceValसंपत्ति मेरे जेपीए प्रदाता द्वारा भी उत्पन्न की जाएगी।

बस चीजों को स्पष्ट करने के लिए: मैं चाहता हूं कि हाइबरनेटmySequencedValue संपत्ति के लिए मूल्य उत्पन्न करें । मुझे पता है कि हाइबरनेट डेटाबेस-जनरेट किए गए मानों को संभाल सकता है, लेकिन मैं अपनी संपत्ति के मूल्य को उत्पन्न करने के लिए हाइबरनेट के अलावा किसी अन्य ट्रिगर या किसी अन्य चीज का उपयोग नहीं करना चाहता। यदि हाइबरनेट प्राथमिक कुंजियों के लिए मान उत्पन्न कर सकता है, तो यह एक साधारण संपत्ति के लिए क्यों नहीं उत्पन्न हो सकता है?

जवाबों:


76

इस समस्या के जवाब की तलाश में, मैं इस लिंक पर ठोकर खाई

ऐसा लगता है कि हाइबरनेट / जेपीए आपके गैर-आईडी-गुणों के लिए स्वचालित रूप से एक मूल्य बनाने में सक्षम नहीं है। @GeneratedValueसाथ एनोटेशन केवल संयोजन के रूप में प्रयोग किया जाता है @Idऑटो संख्या बनाने के लिए।

@GeneratedValueएनोटेशन सिर्फ हाइबरनेट बताता है कि डेटाबेस यह मान ही पैदा कर रहा है।

उस मंच में सुझाए गए समाधान (या काम के आसपास) उत्पन्न आईडी के साथ एक अलग इकाई बनाने के लिए है, कुछ इस तरह से:

@Entity
सार्वजनिक वर्ग GeneralSequenceNumber {
  @Id
  @GeneratedValue (...)
  निजी लंबी संख्या;
}

@Entity 
सार्वजनिक वर्ग MyEntity {
  @ मैं ..
  निजी लंबी आईडी;

  @एक से एक(...)
  निजी GeneralSequnceNumber myVal;
}

@GeneratedValue के जावा डॉक से: "जेनरेटवैल्यू एनोटेशन एक प्राथमिक कुंजी संपत्ति या एक इकाई के क्षेत्र में लागू किया जा सकता है या Id एनोटेशन के साथ संयोजन में
सुपरक्लास

11
मैंने पाया कि @ कॉलम (कॉलमडिफ़िनिशन = "सीरियल") एकदम सही काम करता है, लेकिन केवल पोस्टग्रेक्यूएल के लिए। मेरे लिए यह सही समाधान था, क्योंकि दूसरी इकाई "बदसूरत" विकल्प है
सर्गेई वेडर्निकोव

@SergeyVedernikov जो बेहद मददगार था । क्या आप इसे एक अलग उत्तर के रूप में पोस्ट करना चाहेंगे? इसने मेरी समस्या को बहुत सरल और प्रभावी ढंग से हल किया।
मैट बॉल

@MattBall मैंने इसे अलग उत्तर के रूप में पोस्ट किया है :) stackoverflow.com/a/10647933/620858
सर्गेई वेदर्निकोव

1
मैंने उन @GeneratedValueक्षेत्रों पर अनुमति देने के लिए एक प्रस्ताव खोला है जो आईडी नहीं हैं। कृपया 2.2 java.net/jira/browse/JPA_SPEC-113
पेटार तहचिव

44

मैंने पाया कि @Column(columnDefinition="serial")सही काम करता है लेकिन केवल PostgreSQL के लिए। मेरे लिए यह सही समाधान था, क्योंकि दूसरी इकाई "बदसूरत" विकल्प है।


नमस्ते, मुझे इस पर स्पष्टीकरण की आवश्यकता होगी। क्या आप मुझे और अधिक बता सकते हैं?
एमबोरसा

2
@Emaborsa columnDefinition=बिट मूल रूप से हाइबरेट से कहता है कि आप कॉलम की परिभाषा को उत्पन्न करने की कोशिश न करें और इसके बजाय आपके द्वारा दिए गए पाठ का उपयोग करें। अनिवार्य रूप से, कॉलम के लिए आपका डीडीएल शाब्दिक रूप से सिर्फ नाम + स्तंभ होगा। इस स्थिति में (PostgreSQL), mycolumn serialएक तालिका में एक मान्य स्तंभ है।
पैट्रिक

7
MySQL के लिए बराबर है@Column(columnDefinition = "integer auto_increment")
रिचर्ड केनार्ड

2
क्या यह ऑटो अपने मूल्य को उत्पन्न करता है? मैंने इस तरह एक फील्ड डेफिनिशन के साथ एक इकाई को जारी रखने की कोशिश की लेकिन इसका कोई मूल्य नहीं था। इसने स्तंभ में एक अशक्त मान फेंका <कॉलम> गैर अशक्त बाधा का उल्लंघन करता है
KyelJmD

7
मैं @Column(insertable = false, updatable = false, columnDefinition="serial")हाइबरनेट को शून्य मान सम्मिलित करने या फ़ील्ड को अपडेट करने की कोशिश करने से रोकता था। यदि आप इसे सीधे उपयोग करने की आवश्यकता है, तो आप एक डालने के बाद उत्पन्न आईडी प्राप्त करने के लिए db को फिर से क्वेरी करने की आवश्यकता है।
रॉबर्ट डि पाओलो

20

मुझे पता है कि यह एक बहुत पुराना प्रश्न है, लेकिन यह सबसे पहले परिणामों पर दिखाया गया है और प्रश्न के बाद से jpa बहुत बदल गई है।

अब यह करने का सही तरीका @Generatedएनोटेशन के साथ है । आप अनुक्रम को परिभाषित कर सकते हैं, उस क्रम में कॉलम में डिफ़ॉल्ट सेट कर सकते हैं और फिर कॉलम को निम्नानुसार मैप कर सकते हैं:

@Generated(GenerationTime.INSERT)
@Column(name = "column_name", insertable = false)

1
इसके लिए अभी भी डेटाबेस द्वारा उत्पन्न मूल्य की आवश्यकता होती है, जो वास्तव में प्रश्न का उत्तर नहीं देता है। 12c से पहले Oracle डेटाबेस के लिए, आपको मूल्य उत्पन्न करने के लिए डेटाबेस ट्रिगर लिखने की आवश्यकता होगी।
बर्नी

9
इसके अलावा, यह एक हाइबरनेट एनोटेशन है, न कि जेपीए।
caarlos0

14

हाइबरनेट निश्चित रूप से इसका समर्थन करता है। डॉक्स से:

"उत्पन्न गुण वे गुण हैं जो डेटाबेस द्वारा उत्पन्न उनके मान हैं। आमतौर पर, हाइबरनेट अनुप्रयोगों को उन वस्तुओं को ताज़ा करने की आवश्यकता होती है जिनमें कोई गुण होते हैं जिनके लिए डेटाबेस मान उत्पन्न कर रहा था। उत्पन्न गुणों को चिह्नित करता है, हालांकि, एप्लिकेशन को हाइबरनेट को यह जिम्मेदारी सौंपता है। अनिवार्य रूप से, जब भी हाइबरनेट एक उत्पन्न होने वाली संपत्तियों को परिभाषित करने वाली इकाई के लिए SQL INSERT या UPDATE जारी करता है, यह तुरंत उत्पन्न मानों को पुनः प्राप्त करने के लिए एक बाद में चयन करता है। "

केवल डालने पर उत्पन्न संपत्तियों के लिए, आपकी संपत्ति मैपिंग (.hbm.xml) इस तरह दिखाई देगी:

<property name="foo" generated="insert"/>

डालने और अपनी संपत्ति मैपिंग (.hbm.xml) को अपडेट करने के लिए बनाई गई संपत्तियों के लिए:

<property name="foo" generated="always"/>

दुर्भाग्यवश, मुझे JPA का पता नहीं है, इसलिए मुझे नहीं पता कि यह सुविधा JPA के माध्यम से उजागर हुई है (मुझे संदेह है कि नहीं)

वैकल्पिक रूप से, आपको संपत्ति को आवेषण और अपडेट से बाहर करने में सक्षम होना चाहिए, और फिर "मैन्युअल रूप से" कॉल session.refresh (आपत्ति); आपके द्वारा सम्मिलित / अद्यतन करने के बाद डेटाबेस से उत्पन्न मूल्य को लोड करने के लिए।

इस प्रकार आप संपत्ति को सम्मिलित और अपडेट स्टेटमेंट में उपयोग करने से बाहर रखेंगे:

<property name="foo" update="false" insert="false"/>

फिर से, मुझे नहीं पता कि क्या जेपीए इन हाइबरनेट सुविधाओं को उजागर करता है, लेकिन हाइबरनेट उनका समर्थन करता है।


1
@Generated एनोटेशन उपरोक्त XML कॉन्फ़िगरेशन से मेल खाती है। देखें हाइबरनेट डॉक्स के इस भाग अधिक जानकारी के लिए।
एरिक

8

यहाँ एक फॉलोअप के रूप में मुझे यह कैसे काम करने के लिए मिला:

@Override public Long getNextExternalId() {
    BigDecimal seq =
        (BigDecimal)((List)em.createNativeQuery("select col_msd_external_id_seq.nextval from dual").getResultList()).get(0);
    return seq.longValue();
}

हाइबरनेट 4.2.19 और अलंकृत के साथ एक प्रकार:SQLQuery sqlQuery = getSession().createSQLQuery("select NAMED_SEQ.nextval seq from dual"); sqlQuery.addScalar("seq", LongType.INSTANCE); return (Long) sqlQuery.uniqueResult();
एरॉन

6

मैंने @PrePersistएनोटेशन का उपयोग करते हुए हाइबरनेट के साथ यूयूआईडी (या अनुक्रम) की पीढ़ी तय की :

@PrePersist
public void initializeUUID() {
    if (uuid == null) {
        uuid = UUID.randomUUID().toString();
    }
}

5

हालाँकि यह एक पुराना धागा है जो मैं अपने समाधान को साझा करना चाहता हूं और उम्मीद है कि इस पर कुछ प्रतिक्रिया मिलेगी। चेतावनी दी है कि मैं केवल कुछ JUnit टेस्टकेस में अपने स्थानीय डेटाबेस के साथ इस समाधान का परीक्षण किया। इसलिए यह अब तक कोई उत्पादक विशेषता नहीं है।

मैंने बिना किसी संपत्ति के साथ Sequence नामक एक कस्टम एनोटेशन शुरू करके मेरे लिए उस मुद्दे को हल किया। यह केवल उन क्षेत्रों के लिए एक मार्कर है जिन्हें एक वृद्धि क्रम से एक मान सौंपा जाना चाहिए।

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Sequence
{
}

इस एनोटेशन का उपयोग करके मैंने अपनी संस्थाओं को चिह्नित किया।

public class Area extends BaseEntity implements ClientAware, IssuerAware
{
    @Column(name = "areaNumber", updatable = false)
    @Sequence
    private Integer areaNumber;
....
}

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

@Entity
@Table(name = "SequenceNumber", uniqueConstraints = { @UniqueConstraint(columnNames = { "className" }) })
public class SequenceNumber
{
    @Id
    @Column(name = "className", updatable = false)
    private String className;

    @Column(name = "nextValue")
    private Integer nextValue = 1;

    @Column(name = "incrementValue")
    private Integer incrementValue = 10;

    ... some getters and setters ....
}

अंतिम चरण और सबसे कठिन एक PreInsertListener है जो अनुक्रम संख्या असाइनमेंट को संभालता है। ध्यान दें कि मैंने बीन कंटेनर के रूप में वसंत का उपयोग किया।

@Component
public class SequenceListener implements PreInsertEventListener
{
    private static final long serialVersionUID = 7946581162328559098L;
    private final static Logger log = Logger.getLogger(SequenceListener.class);

    @Autowired
    private SessionFactoryImplementor sessionFactoryImpl;

    private final Map<String, CacheEntry> cache = new HashMap<>();

    @PostConstruct
    public void selfRegister()
    {
        // As you might expect, an EventListenerRegistry is the place with which event listeners are registered
        // It is a service so we look it up using the service registry
        final EventListenerRegistry eventListenerRegistry = sessionFactoryImpl.getServiceRegistry().getService(EventListenerRegistry.class);

        // add the listener to the end of the listener chain
        eventListenerRegistry.appendListeners(EventType.PRE_INSERT, this);
    }

    @Override
    public boolean onPreInsert(PreInsertEvent p_event)
    {
        updateSequenceValue(p_event.getEntity(), p_event.getState(), p_event.getPersister().getPropertyNames());

        return false;
    }

    private void updateSequenceValue(Object p_entity, Object[] p_state, String[] p_propertyNames)
    {
        try
        {
            List<Field> fields = ReflectUtil.getFields(p_entity.getClass(), null, Sequence.class);

            if (!fields.isEmpty())
            {
                if (log.isDebugEnabled())
                {
                    log.debug("Intercepted custom sequence entity.");
                }

                for (Field field : fields)
                {
                    Integer value = getSequenceNumber(p_entity.getClass().getName());

                    field.setAccessible(true);
                    field.set(p_entity, value);
                    setPropertyState(p_state, p_propertyNames, field.getName(), value);

                    if (log.isDebugEnabled())
                    {
                        LogMF.debug(log, "Set {0} property to {1}.", new Object[] { field, value });
                    }
                }
            }
        }
        catch (Exception e)
        {
            log.error("Failed to set sequence property.", e);
        }
    }

    private Integer getSequenceNumber(String p_className)
    {
        synchronized (cache)
        {
            CacheEntry current = cache.get(p_className);

            // not in cache yet => load from database
            if ((current == null) || current.isEmpty())
            {
                boolean insert = false;
                StatelessSession session = sessionFactoryImpl.openStatelessSession();
                session.beginTransaction();

                SequenceNumber sequenceNumber = (SequenceNumber) session.get(SequenceNumber.class, p_className);

                // not in database yet => create new sequence
                if (sequenceNumber == null)
                {
                    sequenceNumber = new SequenceNumber();
                    sequenceNumber.setClassName(p_className);
                    insert = true;
                }

                current = new CacheEntry(sequenceNumber.getNextValue() + sequenceNumber.getIncrementValue(), sequenceNumber.getNextValue());
                cache.put(p_className, current);
                sequenceNumber.setNextValue(sequenceNumber.getNextValue() + sequenceNumber.getIncrementValue());

                if (insert)
                {
                    session.insert(sequenceNumber);
                }
                else
                {
                    session.update(sequenceNumber);
                }
                session.getTransaction().commit();
                session.close();
            }

            return current.next();
        }
    }

    private void setPropertyState(Object[] propertyStates, String[] propertyNames, String propertyName, Object propertyState)
    {
        for (int i = 0; i < propertyNames.length; i++)
        {
            if (propertyName.equals(propertyNames[i]))
            {
                propertyStates[i] = propertyState;
                return;
            }
        }
    }

    private static class CacheEntry
    {
        private int current;
        private final int limit;

        public CacheEntry(final int p_limit, final int p_current)
        {
            current = p_current;
            limit = p_limit;
        }

        public Integer next()
        {
            return current++;
        }

        public boolean isEmpty()
        {
            return current >= limit;
        }
    }
}

जैसा कि आप उपरोक्त कोड से देख सकते हैं कि श्रोता प्रति इकाई वर्ग में एक SequenceNumber उदाहरण का उपयोग करता है और अनुक्रम अनुक्रम के incrementValue द्वारा परिभाषित अनुक्रम संख्या के एक जोड़े को आरक्षित करता है। यदि यह अनुक्रम संख्याओं से बाहर निकलता है तो यह लक्ष्य वर्ग के लिए SequenceNumber इकाई को लोड करता है और अगले कॉल के लिए वृद्धिशील मानों को आरक्षित करता है। इस तरह मुझे हर बार अनुक्रम मान की जरूरत है डेटाबेस को क्वेरी करने की आवश्यकता नहीं है। नोट करें कि स्टेटलेस नेशन को अनुक्रम संख्या के अगले सेट को संग्रहीत करने के लिए खोला जा रहा है। आप उसी सत्र का उपयोग नहीं कर सकते हैं जो लक्ष्य इकाई वर्तमान में बनी हुई है क्योंकि इससे EntityPistister में एक समवर्तीमॉडिफिकेशन अपवाद हो जाएगा।

आशा है कि यह किसी की मदद करता है।


5

यदि आप postgresql का उपयोग कर रहे हैं
और मैं वसंत बूट 1.5.6 में उपयोग कर रहा हूं

@Column(columnDefinition = "serial")
@Generated(GenerationTime.INSERT)
private Integer orderID;

1
इसने मेरे लिए भी काम किया, मैं स्प्रिंग बूट 2.1.6 का उपयोग कर रहा हूं। कृपया, हाइबरनेट 5.3.10.Final, इसके अलावा जो पहले ही इंगित कर चुका है, मुझे एक seq_ordernextval('seq_order'::regclass)
सेकंड

3

मैं भी आपकी तरह उसी स्थिति में दौड़ता हूं और मुझे कोई गंभीर जवाब नहीं मिला, अगर मूल रूप से जेपीए के साथ गैर-आईडी संपत्ति उत्पन्न करना संभव है या नहीं।

मेरा समाधान यह है कि एक प्रॉपर्टी को सेट करने से पहले प्रॉपर्टी को सेट करने के लिए एक देशी जेपीए क्वेरी के साथ अनुक्रम को कॉल करें।

यह संतोषजनक नहीं है लेकिन यह फिलहाल के लिए वर्कअराउंड के रूप में काम करता है।

मारियो


2

मुझे यह विशिष्ट नोट सत्र 9 में मिला है। जेपीए विनिर्देशन से 9.1.9 जेनरेटेड वेल्यू एनोटेशन: "[43] पोर्टेबल अनुप्रयोगों को अन्य लगातार क्षेत्रों या संपत्तियों पर जेनरेटवैल्यू एनोटेशन का उपयोग नहीं करना चाहिए।" इसलिए, मैं मानता हूं कि गैर प्राथमिक प्रमुख मूल्यों के लिए ऑटो जेपीए का उपयोग करके कम से कम मूल्य उत्पन्न करना संभव नहीं है।


1

ऐसा लगता है कि धागा पुराना है, मैं बस अपना समाधान यहां जोड़ना चाहता था (वसंत में एस्पेक्ट - एओपी का उपयोग करके)।

समाधान एक कस्टम एनोटेशन बनाने के लिए @InjectSequenceValueनिम्नानुसार है।

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectSequenceValue {
    String sequencename();
}

अब आप इकाई में किसी भी क्षेत्र की व्याख्या कर सकते हैं, ताकि अनुक्रम के अगले अंतराल का उपयोग करके रनटाइम पर अंतर्निहित फ़ील्ड (लॉन्ग / इंटेगर) मान इंजेक्ट किया जाएगा।

इस तरह से एनोटेट।

//serialNumber will be injected dynamically, with the next value of the serialnum_sequence.
 @InjectSequenceValue(sequencename = "serialnum_sequence") 
  Long serialNumber;

अब तक हमने अनुक्रम मान को इंजेक्ट करने के लिए आवश्यक फ़ील्ड को चिह्नित किया है। तो हम देखेंगे कि अनुक्रम फ़ील्ड को अनुक्रम मान को कैसे इंजेक्ट किया जाए, यह AspectJ में पॉइंट कट बनाकर किया जाता है।

हम save/persistविधि निष्पादित होने से ठीक पहले इंजेक्शन को ट्रिगर करेंगे । यह निम्न वर्ग में किया जाता है।

@Aspect
@Configuration
public class AspectDefinition {

    @Autowired
    JdbcTemplate jdbcTemplate;


    //@Before("execution(* org.hibernate.session.save(..))") Use this for Hibernate.(also include session.save())
    @Before("execution(* org.springframework.data.repository.CrudRepository.save(..))") //This is for JPA.
    public void generateSequence(JoinPoint joinPoint){

        Object [] aragumentList=joinPoint.getArgs(); //Getting all arguments of the save
        for (Object arg :aragumentList ) {
            if (arg.getClass().isAnnotationPresent(Entity.class)){ // getting the Entity class

                Field[] fields = arg.getClass().getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(InjectSequenceValue.class)) { //getting annotated fields

                        field.setAccessible(true); 
                        try {
                            if (field.get(arg) == null){ // Setting the next value
                                String sequenceName=field.getAnnotation(InjectSequenceValue.class).sequencename();
                                long nextval=getNextValue(sequenceName);
                                System.out.println("Next value :"+nextval); //TODO remove sout.
                                field.set(arg, nextval);
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        }
    }

    /**
     * This method fetches the next value from sequence
     * @param sequence
     * @return
     */

    public long getNextValue(String sequence){
        long sequenceNextVal=0L;

        SqlRowSet sqlRowSet= jdbcTemplate.queryForRowSet("SELECT "+sequence+".NEXTVAL as value FROM DUAL");
        while (sqlRowSet.next()){
            sequenceNextVal=sqlRowSet.getLong("value");

        }
        return  sequenceNextVal;
    }
}

अब आप नीचे दिए गए किसी भी एंटिटी का सत्यानाश कर सकते हैं।

@Entity
@Table(name = "T_USER")
public class UserEntity {

    @Id
    @SequenceGenerator(sequenceName = "userid_sequence",name = "this_seq")
    @GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "this_seq")
    Long id;
    String userName;
    String password;

    @InjectSequenceValue(sequencename = "serialnum_sequence") // this will be injected at the time of saving.
    Long serialNumber;

    String name;
}

0

"मैं अपनी संपत्ति के मूल्य को उत्पन्न करने के लिए हाइबरनेट के अलावा एक ट्रिगर या किसी अन्य चीज का उपयोग नहीं करना चाहता"

उस स्थिति में, UserType के कार्यान्वयन को बनाने के बारे में कैसे जो आवश्यक मूल्य उत्पन्न करता है, और mySequenceVal संपत्ति की दृढ़ता के लिए उस UserType का उपयोग करने के लिए मेटाडेटा को कॉन्फ़िगर करता है?


0

यह एक अनुक्रम का उपयोग करने के समान नहीं है। अनुक्रम का उपयोग करते समय, आप कुछ भी सम्मिलित या अपडेट नहीं कर रहे हैं। आप बस अगले अनुक्रम मान को पुनः प्राप्त कर रहे हैं। ऐसा लगता है कि हाइबरनेट इसका समर्थन नहीं करता है।


0

यदि आपके पास डालने पर आवश्यक UNIQUEIDENTIFIER प्रकार और डिफ़ॉल्ट पीढ़ी वाला एक कॉलम है, लेकिन स्तंभ PK नहीं है

@Generated(GenerationTime.INSERT)
@Column(nullable = false , columnDefinition="UNIQUEIDENTIFIER")
private String uuidValue;

Db में आपके पास होगा

CREATE TABLE operation.Table1
(
    Id         INT IDENTITY (1,1)               NOT NULL,
    UuidValue  UNIQUEIDENTIFIER DEFAULT NEWID() NOT NULL)

इस मामले में आप जनरेटर को उस मूल्य के लिए परिभाषित नहीं करेंगे जिसकी आपको आवश्यकता है (यह स्वचालित रूप से धन्यवाद होगा columnDefinition="UNIQUEIDENTIFIER")। वही आप अन्य कॉलम प्रकारों के लिए प्रयास कर सकते हैं


0

मैंने इसके लिए MyPql डेटाबेस पर @PostConstruct और JdbcTemplate एक स्प्रिंग एप्लिकेशन का उपयोग करके वर्कअराउंड पाया है। यह अन्य डेटाबेस के साथ संभव हो सकता है, लेकिन मैं जिस केस का उपयोग करता हूं, वह MySql के साथ मेरे अनुभव पर आधारित है, क्योंकि यह auto_increment का उपयोग करता है।

सबसे पहले, मैंने @ कॉलम रिपोर्ट के कॉलमडिफाइनमेंट प्रॉपर्टी का उपयोग करते हुए एक कॉलम को auto_increment के रूप में परिभाषित करने का प्रयास किया था, लेकिन यह ऑटो इंक्रीमेंटल होने के लिए एक कुंजी होने के लिए आवश्यक कॉलम के रूप में काम नहीं कर रहा था, लेकिन स्पष्ट रूप से कॉलम को परिभाषित नहीं किया जाएगा। एक सूचकांक जब तक इसे परिभाषित नहीं किया गया था, तब तक गतिरोध पैदा हो गया था।

यहां वह जगह है जहां मुझे auto_increment परिभाषा के बिना कॉलम बनाने, और इसे जोड़ने का विचार आया डेटाबेस बनाने के बाद था। यह @PostConstruct एनोटेशन का उपयोग करके संभव है, जो आवेदन के बाद सेम को इनिशियलाइज़ करने के लिए एक विधि का कारण बनता है, JdbcTemplate की अपडेट विधि के साथ मिलकर।

कोड इस प्रकार है:

मेरी इकाई में:

@Entity
@Table(name = "MyTable", indexes = { @Index(name = "my_index", columnList = "mySequencedValue") })
public class MyEntity {
    //...
    @Column(columnDefinition = "integer unsigned", nullable = false, updatable = false, insertable = false)
    private Long mySequencedValue;
    //...
}

PostConstructComponent वर्ग में:

@Component
public class PostConstructComponent {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @PostConstruct
    public void makeMyEntityMySequencedValueAutoIncremental() {
        jdbcTemplate.update("alter table MyTable modify mySequencedValue int unsigned auto_increment");
    }
}

0

मैं @Morten बर्ग के स्वीकृत समाधान के बगल में एक विकल्प प्रदान करना चाहता हूं, जिसने मेरे लिए बेहतर काम किया।

यह दृष्टिकोण वास्तव में वांछित Numberप्रकार के साथ क्षेत्र को परिभाषित करने की अनुमति देता है - Longमेरे उपयोग के मामले में - के बजाय GeneralSequenceNumber। यह उपयोगी हो सकता है, उदाहरण के लिए JSON (डी-) क्रमांकन।

नकारात्मक पक्ष यह है कि इसके लिए थोड़ा अधिक डेटाबेस ओवरहेड की आवश्यकता होती है।


सबसे पहले, हमें एक प्रकार की आवश्यकता ActualEntityहै जिसमें हम generatedप्रकार के ऑटो-इंक्रीमेंट चाहते हैं Long:

// ...
@Entity
public class ActualEntity {

    @Id 
    // ...
    Long id;

    @Column(unique = true, updatable = false, nullable = false)
    Long generated;

    // ...

}

अगला, हमें एक सहायक इकाई की आवश्यकता है Generated। मैंने इसे पैकेज के निजीकरण के बगल में रखा, इसे पैकेज ActualEntityका कार्यान्वयन विवरण रखने के लिए:

@Entity
class Generated {

    @Id
    @GeneratedValue(strategy = SEQUENCE, generator = "seq")
    @SequenceGenerator(name = "seq", initialValue = 1, allocationSize = 1)
    Long id;

}

अंत में, हमें बचाने से पहले सही जगह हुक करने की आवश्यकता है ActualEntity। वहां, हम एक Generatedउदाहरण बनाते हैं और उसे बनाए रखते हैं । यह तो एक डेटाबेस-अनुक्रम उत्पन्न प्रदान करता है idप्रकार के Long। हम इसे लिखकर इस मान का उपयोग करते हैंActualEntity.generated

अपने उपयोग के मामले में, मैंने इसे एक स्प्रिंग डेटा रीस्ट का उपयोग करते हुए लागू किया @RepositoryEventHandler, जिसे प्राप्त होने से पहले सही कहा जाता है ActualEntity। यह सिद्धांत प्रदर्शित करना चाहिए:

@Component
@RepositoryEventHandler
public class ActualEntityHandler {

    @Autowired
    EntityManager entityManager;

    @Transactional
    @HandleBeforeCreate
    public void generate(ActualEntity entity) {
        Generated generated = new Generated();

        entityManager.persist(generated);
        entity.setGlobalId(generated.getId());
        entityManager.remove(generated);
    }

}

मैंने इसे वास्तविक जीवन के अनुप्रयोग में नहीं देखा था, इसलिए कृपया इसका ध्यान रखें।


-1

मैं आपके (JPA / Hibernate अनुक्रम के लिए non @Id फ़ील्ड) जैसी स्थिति में हूं और मैंने अपने db स्कीमा में एक ट्रिगर बनाना समाप्त कर दिया है जो सम्मिलित करने पर एक अद्वितीय अनुक्रम संख्या जोड़ता है। मुझे कभी भी जेपीए / हाइबरनेट के साथ काम करने के लिए नहीं मिला


-1

घंटों बिताने के बाद, इसने मेरी समस्या को हल करने में बहुत मदद की:

Oracle 12c के लिए:

ID NUMBER GENERATED as IDENTITY

H2 के लिए:

ID BIGINT GENERATED as auto_increment

यह भी करें:

@Column(insertable = false)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.