Hibernate JPA Sequence (non-Id)

141

Apakah mungkin menggunakan urutan DB untuk beberapa kolom yang bukan pengenal / bukan bagian dari pengenal komposit ?

Saya menggunakan hibernate sebagai penyedia jpa, dan saya memiliki tabel yang memiliki beberapa kolom yang menghasilkan nilai (menggunakan urutan), meskipun mereka bukan bagian dari pengenal.

Yang saya inginkan adalah menggunakan urutan untuk membuat nilai baru untuk entitas, di mana kolom urutan BUKAN (bagian dari) kunci utama:

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

}

Lalu ketika saya melakukan ini:

em.persist(new MyEntity());

id akan dibuat, tetapi mySequenceValproperti juga akan dibuat oleh penyedia JPA saya.

Hanya untuk memperjelas: Saya ingin Hibernate menghasilkan nilai mySequencedValueproperti. Saya tahu Hibernate dapat menangani nilai yang dihasilkan database, tetapi saya tidak ingin menggunakan pemicu atau hal lain selain Hibernate itu sendiri untuk menghasilkan nilai properti saya. Jika Hibernate dapat menghasilkan nilai untuk kunci utama, mengapa tidak dapat menghasilkan untuk properti sederhana?

Miguel Ping
sumber

Jawaban:

78

Mencari jawaban untuk masalah ini, saya menemukan tautan ini

Tampaknya Hibernate / JPA tidak dapat secara otomatis membuat nilai untuk properti non-id Anda. The @GeneratedValuepenjelasan hanya digunakan dalam hubungannya dengan @Idmembuat auto-angka.

The @GeneratedValuepenjelasan hanya memberitahu Hibernate bahwa database adalah menghasilkan nilai ini sendiri.

Solusi (atau solusi) yang disarankan di forum itu adalah membuat entitas terpisah dengan Id yang dihasilkan, seperti ini:

@Kesatuan
kelas publik GeneralSequenceNumber {
  @Indo
  @GeneratedValue (...)
  nomor panjang pribadi;
}

@Kesatuan 
public class MyEntity {
  @Indo ..
  pribadi Long id;

  @OneTone (...)
  pribadi GeneralSequnceNumber myVal;
}
Morten Berg
sumber
Dari dokumen java @GeneratedValue: "Anotasi GeneratedValue dapat diterapkan ke properti atau bidang kunci utama dari entitas atau superclass yang dipetakan bersama dengan anotasi Id"
Kariem
11
Saya menemukan bahwa @Column (columnDefinition = "serial") berfungsi sempurna tetapi hanya untuk PostgreSQL. Bagi saya ini adalah solusi sempurna, karena entitas kedua adalah opsi "jelek"
Sergey Vedernikov
@SergeyVedernikov yang sangat membantu. Maukah Anda mempostingnya sebagai jawaban terpisah? Ini memecahkan masalah saya dengan sangat sederhana dan efektif.
Matt Ball
@MattBall saya telah memposting ini sebagai jawaban terpisah :) stackoverflow.com/a/10647933/620858
Sergey Vedernikov
1
Saya telah membuka proposal untuk diizinkan @GeneratedValuepada bidang yang bukan id. Harap
berikan
47

Saya menemukan itu @Column(columnDefinition="serial")berfungsi sempurna tetapi hanya untuk PostgreSQL. Bagi saya ini adalah solusi yang tepat, karena entitas kedua adalah pilihan yang "jelek".

Panggilan ke saveAndFlushentitas juga diperlukan, dan savetidak akan cukup untuk mengisi nilai dari DB.

Sergey Vedernikov
sumber
Hai, saya butuh penjelasan tentang itu. Bisakah Anda memberi tahu saya lebih banyak?
Emaborsa
2
@Emaborsa columnDefinition=Bit pada dasarnya memberitahu Hiberate untuk tidak mencoba membuat definisi kolom dan sebagai gantinya menggunakan teks yang Anda berikan. Pada dasarnya, DDL Anda untuk kolom secara harfiah hanya berupa name + columnDefinition. Dalam hal ini (PostgreSQL), mycolumn serialadalah kolom yang valid dalam sebuah tabel.
Patrick
7
Setara untuk MySQL adalah@Column(columnDefinition = "integer auto_increment")
Richard Kennard
2
Apakah mobil ini menghasilkan nilainya? Saya mencoba mempertahankan entitas dengan definisi bidang seperti ini tetapi tidak menghasilkan nilai. itu melemparkan nilai null di kolom <column> melanggar kendala non null
KyelJmD
7
Saya dulu @Column(insertable = false, updatable = false, columnDefinition="serial")mencegah hibernasi mencoba memasukkan nilai null atau memperbarui bidang. Anda kemudian perlu membuat kueri ulang db untuk mendapatkan id yang dihasilkan setelah penyisipan jika Anda perlu langsung menggunakannya.
Robert Di Paolo
23

Saya tahu ini adalah pertanyaan yang sangat lama, tetapi ini pertama kali ditunjukkan pada hasil dan jpa telah banyak berubah sejak pertanyaan itu.

Cara yang benar untuk melakukannya sekarang adalah dengan @Generatedanotasi. Anda dapat menentukan urutan, mengatur default di kolom ke urutan itu dan kemudian memetakan kolom sebagai:

@Generated(GenerationTime.INSERT)
@Column(name = "column_name", insertable = false)
Rumal
sumber
1
Ini masih membutuhkan nilai yang akan dihasilkan oleh database, yang tidak benar-benar menjawab pertanyaan tersebut. Untuk database Oracle sebelum 12c, Anda masih perlu menulis pemicu database untuk menghasilkan nilainya.
Bernie
10
juga, ini adalah anotasi Hibernate, bukan JPA.
caarlos0
14

Hibernate pasti mendukung ini. Dari dokumen:

"Properti yang dihasilkan adalah properti yang nilainya dihasilkan oleh database. Biasanya, aplikasi Hibernasi diperlukan untuk menyegarkan objek yang berisi properti apa pun yang nilainya dihasilkan oleh database. Menandai properti yang dihasilkan, bagaimanapun, memungkinkan aplikasi mendelegasikan tanggung jawab ini ke Hibernasi. Pada dasarnya, setiap kali Hibernate mengeluarkan SQL INSERT atau UPDATE untuk entitas yang telah menentukan properti yang dihasilkan, segera mengeluarkan pilihan setelah itu untuk mengambil nilai yang dihasilkan. "

Untuk properti yang dibuat hanya dengan penyisipan, pemetaan properti Anda (.hbm.xml) akan terlihat seperti:

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

Untuk properti yang dihasilkan saat menyisipkan dan memperbarui pemetaan properti Anda (.hbm.xml) akan terlihat seperti:

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

Sayangnya, saya tidak tahu JPA, jadi saya tidak tahu apakah fitur ini diekspos melalui JPA (saya kira mungkin tidak)

Alternatifnya, Anda harus bisa mengecualikan properti dari penyisipan dan pembaruan, dan kemudian "secara manual" memanggil session.refresh (obj); setelah Anda memasukkan / memperbaruinya untuk memuat nilai yang dihasilkan dari database.

Beginilah cara Anda mengecualikan properti agar tidak digunakan dalam pernyataan sisipkan dan perbarui:

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

Sekali lagi, saya tidak tahu apakah JPA mengekspos fitur Hibernate ini, tetapi Hibernate mendukungnya.

alasdairg
sumber
1
Anotasi @Generated sesuai dengan konfigurasi XML di atas. Lihat bagian dokumen hibernasi ini untuk lebih jelasnya.
Eric
8

Sebagai tindak lanjut, inilah cara saya membuatnya berfungsi:

@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();
}
Paul
sumber
Variasi dengan Hibernate 4.2.19 dan oracle: SQLQuery sqlQuery = getSession().createSQLQuery("select NAMED_SEQ.nextval seq from dual"); sqlQuery.addScalar("seq", LongType.INSTANCE); return (Long) sqlQuery.uniqueResult();
Aaron
8

Saya memperbaiki pembuatan UUID (atau urutan) dengan Hibernate menggunakan @PrePersistanotasi:

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

Meskipun ini adalah utas lama, saya ingin membagikan solusi saya dan semoga mendapatkan umpan balik tentang ini. Berhati-hatilah karena saya hanya menguji solusi ini dengan database lokal saya di beberapa kasus pengujian JUnit. Jadi ini bukan fitur produktif sejauh ini.

Saya memecahkan masalah itu untuk saya dengan memperkenalkan anotasi khusus yang disebut Urutan tanpa properti. Itu hanya penanda untuk bidang yang harus diberi nilai dari urutan yang bertambah.

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

Menggunakan anotasi ini saya menandai entitas saya.

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

Untuk menjaga agar database tetap independen, saya memperkenalkan entitas yang disebut SequenceNumber yang memegang urutan nilai saat ini dan ukuran kenaikan. Saya memilih className sebagai kunci unik sehingga setiap kelas entitas akan mendapatkan urutannya sendiri.

@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 ....
}

Langkah terakhir dan yang paling sulit adalah PreInsertListener yang menangani penetapan nomor urut. Perhatikan bahwa saya menggunakan pegas sebagai wadah kacang.

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

Seperti yang Anda lihat dari kode di atas, pendengar menggunakan satu instance SequenceNumber per kelas entitas dan menyimpan beberapa nomor urut yang ditentukan oleh incrementValue dari entitas SequenceNumber. Jika kehabisan nomor urut, ia memuat entitas SequenceNumber untuk kelas target dan mencadangkan nilai incrementValue untuk panggilan berikutnya. Dengan cara ini saya tidak perlu meminta database setiap kali nilai urutan diperlukan. Perhatikan StatelessSession yang sedang dibuka untuk memesan rangkaian nomor urut berikutnya. Anda tidak dapat menggunakan sesi yang sama dengan entitas target yang saat ini dipertahankan karena ini akan mengarah ke ConcurrentModificationException di EntityPersister.

Semoga ini bisa membantu seseorang.

Sebastian Götz
sumber
5

Jika Anda menggunakan postgresql
Dan saya menggunakan di boot musim semi 1.5.6

@Column(columnDefinition = "serial")
@Generated(GenerationTime.INSERT)
private Integer orderID;
Sulaymon Hursanov
sumber
1
Ini bekerja untuk saya juga, saya menggunakan boot musim semi 2.1.6. RELEASE, Hibernate 5.3.10. Final, Selain apa yang telah ditunjukkan, saya harus membuat keamanan seq_orderdan membuat referensi dari lapangan, nextval('seq_order'::regclass)
OJVM
3

Saya menjalankan dalam situasi yang sama seperti Anda dan saya juga tidak menemukan jawaban yang serius apakah pada dasarnya memungkinkan untuk menghasilkan properti non-id dengan JPA atau tidak.

Solusi saya adalah memanggil urutan dengan permintaan JPA asli untuk mengatur properti dengan tangan sebelum bertahan.

Ini tidak memuaskan tetapi berfungsi sebagai solusi untuk saat ini.

Mario


sumber
2

Saya telah menemukan catatan khusus ini di sesi 9.1.9 Anotasi GeneratedValue dari spesifikasi JPA: "[43] Aplikasi portabel tidak boleh menggunakan anotasi GeneratedValue pada bidang atau properti lain yang persisten." Jadi, saya berasumsi bahwa tidak mungkin menghasilkan nilai secara otomatis untuk nilai kunci non primer setidaknya menggunakan JPA saja.

Gustavo Orair
sumber
1

Sepertinya utas sudah tua, saya hanya ingin menambahkan solusi saya di sini (Menggunakan AspectJ - AOP di musim semi).

Solusinya adalah membuat anotasi kustom @InjectSequenceValuesebagai berikut.

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

Sekarang Anda dapat membuat anotasi bidang apa pun dalam entitas, sehingga nilai bidang yang mendasarinya (Panjang / Bilangan bulat) akan dimasukkan saat runtime menggunakan nilai berikutnya dari urutan tersebut.

Beri anotasi seperti ini.

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

Sejauh ini kita telah menandai field yang kita butuhkan untuk menginjeksi nilai sequence. Jadi kita akan melihat bagaimana menginjeksi nilai sequence ke field yang ditandai, ini dilakukan dengan membuat point cut di AspectJ.

Kami akan memicu injeksi sebelum save/persistmetode ini dijalankan. Ini dilakukan di kelas di bawah ini.

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

Sekarang Anda dapat membuat anotasi Entitas apa pun seperti di bawah ini.

@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;
}
Subin Chalil
sumber
0

"Saya tidak ingin menggunakan pemicu atau hal lain selain Hibernasi itu sendiri untuk menghasilkan nilai properti saya"

Dalam kasus tersebut, bagaimana dengan membuat implementasi UserType yang menghasilkan nilai yang diperlukan, dan mengonfigurasi metadata untuk menggunakan UserType tersebut untuk persistensi properti mySequenceVal?

alasdairg
sumber
0

Ini tidak sama dengan menggunakan urutan. Saat menggunakan urutan, Anda tidak memasukkan atau memperbarui apa pun. Anda hanya mengambil nilai urutan berikutnya. Sepertinya hibernasi tidak mendukungnya.

kammy
sumber
0

Jika Anda memiliki kolom dengan tipe UNIQUEIDENTIFIER dan pembuatan default diperlukan pada penyisipan tetapi kolom bukan PK

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

Dalam db Anda akan memiliki

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

Dalam hal ini Anda tidak akan menentukan generator untuk nilai yang Anda butuhkan (Ini akan otomatis berkat columnDefinition="UNIQUEIDENTIFIER"). Hal yang sama dapat Anda coba untuk jenis kolom lainnya

Artyom Novitskii
sumber
0

Saya telah menemukan solusi untuk ini di database MySql menggunakan @PostConstruct dan JdbcTemplate dalam aplikasi Spring. Ini mungkin bisa dilakukan dengan database lain tetapi kasus penggunaan yang akan saya sajikan didasarkan pada pengalaman saya dengan MySql, karena menggunakan auto_increment.

Pertama, saya telah mencoba mendefinisikan kolom sebagai auto_increment menggunakan properti ColumnDefinition dari anotasi @Column, tetapi itu tidak berfungsi karena kolom harus menjadi kunci agar menjadi penambahan otomatis, tetapi tampaknya kolom tidak akan didefinisikan sebagai indeks sampai setelah itu didefinisikan, menyebabkan kebuntuan.

Di sinilah saya mendapatkan ide untuk membuat kolom tanpa definisi auto_increment, dan menambahkannya setelahnya database dibuat. Hal ini dimungkinkan menggunakan anotasi @PostConstruct, yang menyebabkan metode dipanggil tepat setelah aplikasi menginisialisasi kacang, digabungkan dengan metode update JdbcTemplate.

Kodenya adalah sebagai berikut:

Dalam Entitas Saya:

@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;
    //...
}

Di kelas PostConstructComponent:

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

    @PostConstruct
    public void makeMyEntityMySequencedValueAutoIncremental() {
        jdbcTemplate.update("alter table MyTable modify mySequencedValue int unsigned auto_increment");
    }
}
Ignacio Velásquez Lagos
sumber
0

Saya ingin memberikan alternatif di samping solusi yang diterima @Morten Berg, yang bekerja lebih baik untuk saya.

Pendekatan ini memungkinkan untuk menentukan bidang dengan jenis yang sebenarnya diinginkan Number- Longdalam kasus penggunaan saya - alih-alih GeneralSequenceNumber. Ini dapat berguna, misalnya untuk serialisasi JSON (de-).

Sisi negatifnya adalah ia membutuhkan sedikit lebih banyak overhead database.


Pertama, kita membutuhkan ActualEntitydi mana kita ingin auto-increment generatedtype Long:

// ...
@Entity
public class ActualEntity {

    @Id 
    // ...
    Long id;

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

    // ...

}

Selanjutnya, kita membutuhkan entitas pembantu Generated. Saya meletakkannya package-private di sebelah ActualEntity, untuk menjadikannya sebagai detail implementasi dari paket:

@Entity
class Generated {

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

}

Akhirnya, kita membutuhkan tempat untuk menghubungkan sebelum kita menyimpan file ActualEntity. Di sana, kami membuat dan mempertahankan sebuah Generatedinstance. Ini kemudian menyediakan urutan database yang dihasilkan iddari tipe Long. Kami memanfaatkan nilai ini dengan menuliskannya ke ActualEntity.generated.

Dalam kasus penggunaan saya, saya menerapkan ini menggunakan REST Data Musim Semi @RepositoryEventHandler, yang dipanggil tepat sebelum ActualEntityget dipertahankan. Ini harus menunjukkan prinsip:

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

}

Saya tidak mengujinya dalam aplikasi kehidupan nyata, jadi nikmati dengan hati-hati.

aboger
sumber
0

Saya berjuang dengan ini hari ini, bisa menyelesaikannya menggunakan ini

@Generated(GenerationTime.INSERT)
@Column(name = "internal_id", columnDefinition = "serial", updatable = false)
private int internalId;
Aritra Das
sumber
-1

Saya pernah berada dalam situasi seperti Anda (urutan JPA / Hibernate untuk bidang non @Id) dan saya akhirnya membuat pemicu dalam skema db saya yang menambahkan nomor urut unik pada penyisipan. Saya tidak pernah membuatnya bekerja dengan JPA / Hibernate

Frederic Morin
sumber
-1

Setelah menghabiskan berjam-jam, ini dengan rapi membantu saya memecahkan masalah saya:

Untuk Oracle 12c:

ID NUMBER GENERATED as IDENTITY

Untuk H2:

ID BIGINT GENERATED as auto_increment

Buat juga:

@Column(insertable = false)
Musim semi
sumber