Hazırda Bekletme'de ayrılmış nesneleri yeniden eklemenin doğru yolu nedir?


186

Ben aynı kimliğe sahip bir nesne zaten oturumda, hatalara neden olabilir zaten mevcut olsa da, bir hazırda bekletme nesneleri bir hazırda bekleme oturumu yeniden eklemek gerekir bir durum var.

Şu anda iki şeyden birini yapabilirim.

  1. getHibernateTemplate().update( obj ) Bu, yalnızca hazırda bekletme oturumunda bir nesne yoksa çalışır. İstisnalar, daha sonra ihtiyaç duyduğumda oturumda zaten belirtilen tanımlayıcıya sahip bir nesneyi belirten atılır.

  2. getHibernateTemplate().merge( obj ) Bu, yalnızca hazırda bekletme oturumunda bir nesne varsa çalışır. Bunu kullanırsam daha sonra nesnenin bir oturumda olmasını istediğimde istisnalar atılır.

Bu iki senaryo göz önüne alındığında, oturumları nesnelere nasıl genel olarak ekleyebilirim? Daha zarif bir çözüm olması gerektiğinden, bu sorunun çözümünün akışını kontrol etmek için istisnalar kullanmak istemiyorum ...

Yanıtlar:


181

Öyleyse JPA'da eski bir müstakil varlığı yeniden bağlamanın bir yolu yok gibi görünüyor.

merge() eski durumu DB'ye gönderir ve müdahale eden güncellemelerin üzerine yazar.

refresh() müstakil bir varlık için çağrılamaz.

lock() müstakil bir varlık üzerinde çağrılamaz ve bu mümkün olsa bile, varlığı kilitler, kilitlemediğinizi, ancak kilitlemediğinizi ima eden 'LockMode.NONE' argümanı ile 'lock' çağırır. Şimdiye kadar gördüğüm.

Yani sıkışıp kaldın. Bir detach()yöntem var ama yok attach()ya da reattach(). Nesne yaşam döngüsünde aşikar bir adım kullanamazsınız.

JPA ile ilgili benzer soruların sayısına bakılırsa, JPA tutarlı bir modele sahip olduğunu iddia etse bile, kesinlikle nasıl elde edileceğini anlamaya çalışarak saatlerce boşa harcanan çoğu programcının zihinsel modeliyle eşleşmiyor gibi görünüyor. JPA en basit şeyleri yapmak ve tüm uygulamaları üzerinde önbellek yönetimi kodu ile sonuçlanır.

Bunu yapmanın tek yolu, eski müstakil varlığınızı atmak ve L2 veya DB'yi vuracak aynı kimliğe sahip bir arama sorgusu yapmak gibi görünüyor.

Mik


1
Acaba JPA spec refresh()müstakil varlıklara izin vermiyor bir nedeni var mı? 2.0 spec bakarak herhangi bir gerekçe görmüyorum; sadece izin verilmiyor.
FGreg

11
Bu kesinlikle doğru DEĞİLDİR. JPwH sitesinden: *Reattaching a modified detached instance* A detached instance may be reattached to a new Session (and managed by this new persistence context) by calling update() on the detached object. In our experience, it may be easier for you to understand the following code if you rename the update() method in your mind to reattach()—however, there is a good reason it’s called updating.Daha fazla bilgi bölüm 9.3.2
cwash

Kalıcı nesneler harika çalışır, kirli bayrak, ilk yük ile yıkama () sırasındaki değer (ler) arasındaki delta temel alınarak ayarlanır. Ayrılmış nesneler gerekir ve şu anda bu işlevselliğe sahip değildir. Hazırda bekletme modunun bunu yapmanın yolu, ayrılmış nesneler için ek bir karma / kimlik eklemektir. Ve aynı kalıcı nesneler için olduğu gibi, ayrılmış nesnenin son durumunun anlık görüntüsünü tutun. Böylece mevcut tüm kodlardan yararlanabilir ve ayrıştırılmış nesneler için çalışmasını sağlayabilirler. Bu şekilde mikhailfranco'nun belirttiği gibi "eski durumu DB'ye aktarmayacağız ve herhangi bir müdahale eden güncellemenin üzerine yazmayacağız"
tom

2
Hibernate javadoc'a göre (JPA değil), lock(LockMode.NONE)aslında geçici bir nesne üzerinde çağrılabilir ve varlığı oturuma yeniden bağlar. Bkz. Stackoverflow.com/a/3683370/14379
seanf

kilit benim için çalışmadı: org.hibernate.internal.SessionImpl.lock (SessionImpl.java:3491) org.hibernate.internal.SessionImpl.lock (SessionImpl.lock (SessionImpl.lock) adresindeki kalıcılık bağlamında olmayan java.lang.IllegalArgumentException: varlık işe yaramadı. java: 3482) com.github.vok.framework.DisableTransactionControlEMDelegate.lock (DB.kt)
Martin Vysny

32

Bütün bu cevaplar önemli bir ayrımı kaçırıyor. update (), nesne grafiğinizi bir Oturuma eklemek (yeniden) için kullanılır. Oradan geçirdiğiniz nesneler yönetilen nesnelerdir.

merge () aslında bir (yeniden) ek API değildir. Merge () öğesinin dönüş değeri olduğuna dikkat edin? Bunun nedeni, size ilettiğiniz grafik olmayabilir, yönetilen grafiği döndürür. merge () bir JPA API'sıdır ve davranışı JPA spesifikasyonu tarafından yönetilir. Merge () öğesine ilettiğiniz nesne zaten yönetiliyorsa (zaten Oturum ile ilişkilendirilmişse) Hazırda Bekletme'nin çalıştığı grafik budur; iletilen nesne merge () öğesinden döndürülen nesne ile aynıdır. Ancak, merge () öğesine ilettiğiniz nesne ayrılırsa, Hazırda Beklet, yönetilen yeni bir nesne grafiği oluşturur ve ayrıştırılmış grafiğinizden durumu yeni yönetilen grafiğe kopyalar. Yine, bunların hepsi JPA şartnamesi tarafından belirlenir ve yönetilir.

"Bu varlığın yönetildiğinden emin olun veya yönetin" için genel bir strateji açısından, henüz eklenmemiş verileri de hesaba katmak isteyip istemediğinize bağlıdır. Yaptığınızı varsayarak,

if ( session.contains( myEntity ) ) {
    // nothing to do... myEntity is already associated with the session
}
else {
    session.saveOrUpdate( myEntity );
}

Update () yerine saveOrUpdate () kullandığım dikkat edin. Henüz eklenmemiş verilerin burada işlenmesini istemiyorsanız bunun yerine update () öğesini kullanın ...


3
Bu soruya doğru cevap bu - dava kapandı!
cwash

2
Session.contains(Object)referans ile kontrol eder. Oturumda aynı satırı temsil eden başka bir Varlık varsa ve bağımsız bir örneği iletirseniz bir istisna alırsınız.
djmj

Session.contains(Object)Referans olarak yapılan kontroller olarak , oturumda aynı satırı temsil eden başka bir Varlık varsa, yanlış döndürür ve günceller.
AxelWass

19

Diplomatik cevap: Muhtemelen genişletilmiş bir kalıcılık bağlamı arıyorsunuz. Bu, Dikiş Çerçevesinin arkasındaki ana nedenlerden biridir ... Özellikle İlkbaharda Hazırda Bekletme'yi kullanmakta zorlanıyorsanız, bu Seam'in belgelerine bakın.

Diplomatik cevap: Bu, Hazırda Bekletme belgelerinde açıklanmaktadır . Daha fazla açıklamaya ihtiyacınız varsa , Hazırda Bekletme ile Java Kalıcılığı "Müstakil Nesnelerle Çalışma" adlı 9.3.3 bölümüne bakın . Ben ediyorum şiddetle sen hazırda ile CRUD daha fazla bir şey yapıyoruz eğer bu kitabı almak önerilir.


5
Gönderen seamframework.org : "bağlantısını dikiş dokümanlarının bu parçayı" "Dikiş 3'ün Aktif gelişme Red Hat tarafından durdurulmuştur." De öldü.
badbishop

14

Varlığınızın değiştirilmediğinden eminseniz (veya herhangi bir değişikliğin kaybedileceğini kabul ediyorsanız), kilitli olarak oturuma yeniden bağlayabilirsiniz.

session.lock(entity, LockMode.NONE);

Hiçbir şey kilitlenmeyecek, ancak varlığı oturum önbelleğinden alacak veya (orada bulunmuyorsa) DB'den okuyacaktır.

İlişkileri bir "eski" (örneğin HttpSession'dan) nesneler arasında dolaşırken LazyInitException'ı önlemek çok yararlıdır. Öncelikle varlığı "yeniden eklersiniz".

Get özelliğini kullanmak, miras eşleştirildiğinde (getId () üzerinde zaten bir istisna atar) dışında da işe yarayabilir.

entity = session.get(entity.getClass(), entity.getId());

2
Bir varlığı oturumla yeniden ilişkilendirmek istiyorum. Ne yazık ki, Session.lock(entity, LockMode.NONE)istisna söyleyerek başarısız olur: başlatılmamış geçici koleksiyonu yeniden ilişkilendiremedi. Bunun üstesinden nasıl gelebilir?
dma_k

1
Aslında tamamen doğru değildim. Lock () öğesini kullanarak varlığınızı yeniden bağlar, ancak ona bağlı olan diğer varlıkları yeniden bağlamaz. Entity.getOtherEntity (). GetYetAnotherEntity () yaparsanız, bir LazyInit istisnanız olabilir. Bunun üstesinden gelmenin tek yolunu bulmak. entity = em.find (entity.getClass (), entity.getId ();
John Rizzo

Session.find()API yöntemi yoktur . Belki de demek istiyorsun Session.load(Object object, Serializable id).
dma_k

11

Bu çok yaygın bir soru olduğundan, bu cevabın dayandığı bu makaleyi yazdım .

Varlık durumları

JPA aşağıdaki varlık durumlarını tanımlar:

Yeni (Geçici)

Bir Hazırda Bekletme Session(aka Persistence Context) ile ilişkilendirilmemiş ve herhangi bir veritabanı tablosu satırıyla eşlenmemiş yeni oluşturulan bir nesnenin Yeni (Geçici) durumunda olduğu kabul edilir.

Kalıcı olmak için ya EntityManager#persistyöntemi açıkça çağırmamız ya da geçişli kalıcılık mekanizmasını kullanmamız gerekir.

Kalıcı (Yönetilen)

Kalıcı bir varlık, bir veritabanı tablosu satırıyla ilişkilendirildi ve şu anda çalışan Persistence Context tarafından yönetiliyor. Bu tür bir varlıkta yapılan herhangi bir değişiklik tespit edilecek ve veritabanına yayılacaktır (Oturum boşaltma süresi boyunca).

Hazırda Bekletme ile artık INSERT / UPDATE / DELETE deyimlerini yürütmemiz gerekmiyor. Hazırda Beklet, işlemsel bir yazma arkası çalışma stili kullanır ve değişiklikler, en son sorumlu anda, geçerli Sessionyıkama zamanı sırasında senkronize edilir .

bağımsız

Çalışmakta olan Persistence Context kapatıldığında, önceden yönetilen tüm varlıklar ayrılır. Art arda yapılan değişiklikler artık izlenmeyecek ve otomatik veritabanı senkronizasyonu gerçekleşmeyecektir.

Varlık durumu geçişleri

Varlık durumunu, EntityManagerarabirim tarafından tanımlanan çeşitli yöntemleri kullanarak değiştirebilirsiniz .

JPA varlık durumu geçişlerini daha iyi anlamak için aşağıdaki diyagramı göz önünde bulundurun:

JPA varlık durumu geçişleri

JPA kullanırken, ayrılmış bir objeyi bir aktifle yeniden ilişkilendirmek EntityManageriçin birleştirme işlemini kullanabilirsiniz .

Yerel Hazırda Bekletme API'sını kullanırken, ayrı mergebir varlığı aşağıdaki diyagramda gösterildiği gibi güncelleme yöntemlerini kullanarak etkin bir Hazırda Bekletme Oturumuna yeniden bağlayabilirsiniz:

Hazırda bekletme durumu geçişleri

Ayrılmış bir varlığı birleştirme

Birleştirme, ayrılmış varlık durumunu (kaynak) yönetilen varlık örneğine (hedef) kopyalayacaktır.

Aşağıdaki Bookvarlığı sürdürdüğümüzü düşünün ve şimdi işletme, EntityManagerişletmenin kapanmasına devam etmek için kullanıldığından ayrılmıştır :

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

Varlık müstakil durumdayken, onu aşağıdaki gibi değiştiririz:

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

Şimdi, değişiklikleri veritabanına yaymak istiyoruz, böylece mergeyöntemi çağırabiliriz :

doInJPA(entityManager -> {
    Book book = entityManager.merge(_book);

    LOGGER.info("Merging the Book entity");

    assertFalse(book == _book);
});

Hazırda Bekletme, aşağıdaki SQL deyimlerini yürütür:

SELECT
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM
    book b
WHERE
    b.id = 1

-- Merging the Book entity

UPDATE
    book
SET
    author = 'Vlad Mihalcea',
    isbn = '978-9730228236',
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE
    id = 1

Birleştirilen varlığın geçerli eşdeğeri yoksa EntityManager, veritabanından yeni bir varlık anlık görüntüsü alınır.

Yönetilen bir varlık olduğunda, JPA ayrılmış varlığın durumunu şu anda yönetilene kopyalar ve Kalıcılık Bağlamıflush sırasında , kirli kontrol mekanizması yönetilen varlığın değiştiğini tespit ederse bir UPDATE oluşturulur .

Bu nedenle, kullanıldığında merge, ayrılmış nesne örneği birleştirme işleminden sonra bile ayrılmaya devam eder.

Ayrılmış bir varlığın yeniden takılması

Hazırda bekletme, ancak JPA updateyöntemde yeniden eklemeyi desteklemez .

Hazırda Bekletme Session, belirli bir veritabanı satırı için yalnızca bir varlık nesnesini ilişkilendirebilir. Bunun nedeni Kalıcılık Bağlamının bir bellek içi önbellek (birinci düzey önbellek) görevi görmesi ve belirli bir anahtarla (varlık türü ve veritabanı tanımlayıcısı) yalnızca bir değerin (varlık) ilişkilendirilmesidir.

Varlık yalnızca geçerli Hazırda Bekletme ile ilişkilendirilmiş başka bir JVM nesnesi (aynı veritabanı satırıyla eşleşen) yoksa yeniden bağlanabilir Session.

İşletmeyi ısrar Bookettiğimizi ve Bookişletme ayrık durumdayken değiştirdiğimizi dikkate alarak :

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

Ayrılmış varlığı şu şekilde yeniden bağlayabiliriz:

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);

    LOGGER.info("Updating the Book entity");
});

Ve Hazırda Beklet aşağıdaki SQL deyimini yürütür:

-- Updating the Book entity

UPDATE
    book
SET
    author = 'Vlad Mihalcea',
    isbn = '978-9730228236',
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE
    id = 1

updateYöntem gerektirir bir hazırda için .unwrapEntityManagerSession

Aksine merge, sağlanan müstakil varlık mevcut Kalıcılık Bağlamıyla yeniden ilişkilendirilir ve varlığın değiştirilip değiştirilmediğine bakılmak üzere bir UPDATE programlanır.

Bunu önlemek için @SelectBeforeUpdate, daha sonra kirli kontrol mekanizması tarafından kullanılan yüklü durumu getiren bir SELECT deyimini tetikleyecek Hazırda Bekletme notunu kullanabilirsiniz .

@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {

    //Code omitted for brevity
}

NonUniqueObjectException özelliğine dikkat edin

Oluşabilecek bir sorun update, Kalıcılık Bağlamının aşağıdaki örnekte olduğu gibi aynı kimliğe ve aynı türe sahip bir varlık başvurusu içermesidir:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);

    return book;
});

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

try {
    doInJPA(entityManager -> {
        Book book = entityManager.find(
            Book.class,
            _book.getId()
        );

        Session session = entityManager.unwrap(Session.class);
        session.saveOrUpdate(_book);
    });
} catch (NonUniqueObjectException e) {
    LOGGER.error(
        "The Persistence Context cannot hold " +
        "two representations of the same entity",
        e
    );
}

Şimdi, yukarıdaki test senaryosunu yürütürken, Hazırda Beklet öğesi bir atar NonUniqueObjectExceptionçünkü ikincisi EntityManagerzaten Bookgeçtiğimizle aynı tanımlayıcıya sahip bir varlık içerdiğinden updateve Kalıcılık Bağlamı aynı varlığın iki temsilini tutamaz.

org.hibernate.NonUniqueObjectException:
    A different object with the same identifier value was already associated with the session : [com.vladmihalcea.book.hpjp.hibernate.pc.Book#1]
    at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:651)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:682)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:674)

Sonuç

mergeYöntem kayıp güncellemeleri engellemek etme olanağı sağladığından iyimser kilitleme kullanıyorsanız tercih edilmelidir. Bu konu hakkında daha fazla bilgi için bu makaleye göz atın .

İşlem updatetarafından oluşturulan ek SELECT deyimini engelleyebileceğinden merge, toplu güncelleştirme yürütme süresini azaltabileceği için toplu güncelleştirmeler için iyidir .


Güzel cevap. @SelectBeforeUpdateAncak ek açıklama merak ediyordum . Seçim ne zaman tetiklenir? Arama sırasında update, yıkamadan hemen önce veya gerçekten önemli değil (hazırda bekletme modunun kızarmadan önce bir açıklamada tüm açıklamalı objeleri getirmesi önemli olabilir)?
Andronicus

@SelectBeforeUpdateSebat Bağlam sırasında SEÇ tetikler flushoperasyon. Daha fazla ayrıntı için içindeki getDatabaseSnapshotyöntemeDefaultFlushEntityEventListener göz atın .
Vlad Mihalcea

10

JavaDoc için geri döndü org.hibernate.Sessionve aşağıdakileri buldum:

Geçici örnekleri arayarak kalıcı yapılabilir save(), persist()ya da saveOrUpdate(). Kalıcı durumlar çağrılarak geçici hale getirilebilir delete(). Bir get()veya load()yöntemiyle döndürülen tüm örnekler kalıcıdır. Müstakil örneklerini arayarak kalıcı yapılabilir update(), saveOrUpdate(), lock()veya replicate(). Geçici veya bağımsız bir örneğin durumu çağrılarak yeni bir kalıcı örnek olarak kalıcı hale getirilebilir merge().

Böylece update(), saveOrUpdate(), lock(), replicate()ve merge()aday seçeneklerdir.

update(): Aynı tanımlayıcıya sahip kalıcı bir örnek varsa bir istisna atar.

saveOrUpdate(): Kaydet veya güncelle

lock(): Kullanımdan kaldırıldı

replicate(): Geçerli tanımlayıcı değerini yeniden kullanarak, verilen bağımsız örneğin durumunu devam ettirir.

merge(): Aynı tanımlayıcıya sahip kalıcı bir nesne döndürür. Belirtilen örnek oturumla ilişkilendirilmez.

Bu nedenle, lock()doğrudan kullanılmamalıdır ve fonksiyonel gereksinime dayanarak bunlardan bir veya daha fazlası seçilebilir.


7

NHibernate ile C # bu şekilde yaptım, ama Java aynı şekilde çalışması gerekir:

public virtual void Attach()
{
    if (!HibernateSessionManager.Instance.GetSession().Contains(this))
    {
        ISession session = HibernateSessionManager.Instance.GetSession();
        using (ITransaction t = session.BeginTransaction())
        {
            session.Lock(this, NHibernate.LockMode.None);
            t.Commit();
        }
    }
}

İlk Kilit her nesneye çağrıldı çünkü Contains her zaman yanlıştı. Sorun NHibernate nesnelerini veritabanı kimliği ve türüne göre karşılaştırmasıdır. İçerik, equalsüzerine yazılmadığı takdirde referans ile karşılaştırılan yöntemi kullanır . Bu equalsyöntemle istisnasız çalışır:

public override bool Equals(object obj)
{
    if (this == obj) { 
        return true;
    } 
    if (GetType() != obj.GetType()) {
        return false;
    }
    if (Id != ((BaseObject)obj).Id)
    {
        return false;
    }
    return true;
}

4

Session.contains(Object obj) referansı kontrol eder ve aynı satırı temsil eden ve buna zaten eklenmiş farklı bir örneği algılamaz.

Tanıtıcı özelliği olan Varlıklar için genel çözümüm.

public static void update(final Session session, final Object entity)
{
    // if the given instance is in session, nothing to do
    if (session.contains(entity))
        return;

    // check if there is already a different attached instance representing the same row
    final ClassMetadata classMetadata = session.getSessionFactory().getClassMetadata(entity.getClass());
    final Serializable identifier = classMetadata.getIdentifier(entity, (SessionImplementor) session);

    final Object sessionEntity = session.load(entity.getClass(), identifier);
    // override changes, last call to update wins
    if (sessionEntity != null)
        session.evict(sessionEntity);
    session.update(entity);
}

Bu, .Net EntityFramework gibi birkaç yönlerinden biri, değişen varlıklar ve özellikleri ile ilgili farklı ekleme seçenekleri.


3

Ben zaten oturuma bağlı olabilir diğer nesneleri açıklayacak kalıcılık deposundan bir nesneyi "yenilemek" için bir çözüm geldi:

public void refreshDetached(T entity, Long id)
{
    // Check for any OTHER instances already attached to the session since
    // refresh will not work if there are any.
    T attached = (T) session.load(getPersistentClass(), id);
    if (attached != entity)
    {
        session.evict(attached);
        session.lock(entity, LockMode.NONE);
    }
    session.refresh(entity);
}

2

Üzgünüz, henüz yorum ekleyemiyor gibi görünüyor (henüz?).

Hazırda Beklet 3.5.0 Son Kullanma

Oysa Session#lockbu kullanımdan kaldırıldı yöntemle javadoc gelmez kullanarak önermek Session#buildLockRequest(LockOptions)#lock(entity)ve emin senin dernekler var yaparsanız cascade=lock, yükleme tembel ya bir sorun değildir.

Bu yüzden ekleme yöntemim biraz benziyor

MyEntity attach(MyEntity entity) {
    if(getSession().contains(entity)) return entity;
    getSession().buildLockRequest(LockOptions.NONE).lock(entity);
    return entity;

İlk testler tedavinin işe yaradığını gösteriyor.


2

Eclipselink'te belki biraz farklı davranır. Eski verileri almadan ayrıştırılmış nesneleri yeniden eklemek için genellikle şunu yaparım:

Object obj = em.find(obj.getClass(), id);

ve isteğe bağlı olarak ikinci bir adım (önbellekleri geçersiz kılmak için):

em.refresh(obj)

1

getHibernateTemplate (). replicate (varlık, ReplicationMode.LATEST_VERSION) öğesini deneyin


1

Orijinal gönderide, iki yöntem vardır update(obj)ve merge(obj)bunlardan işe yaradığı söylenir, ancak tersi durumlarda. Bu gerçekten doğruysa, o zaman neden nesnenin zaten oturumda olup olmadığını test etmeyip, sonra da arayın update(obj), aksi takdirde arayın merge(obj).

Oturumda var olma testi session.contains(obj). Bu nedenle, aşağıdaki sözde kod işe yarayacağını düşünürdüm:

if (session.contains(obj))
{
    session.update(obj);
}
else 
{
    session.merge(obj);
}

2
içerir (), karşılaştırmaları referans ile karşılaştırır, ancak hazırda bekletme işlevleri veritabanı kimliğiyle çalışır. session.merge hiçbir zaman kodunuzda çağrılmaz.
Verena Haunschmid

1

bu nesneyi yeniden bağlamak için merge ();

bu metot, parametrenizde varlığınızın ayrılmasını kabul eder ve bir varlığı iade eder ve Veritabanından eklenir ve yeniden yüklenir.

Example :
    Lot objAttach = em.merge(oldObjDetached);
    objAttach.setEtat(...);
    em.persist(objAttach);

0

ilk merge () (kalıcı örneği güncellemek için) çağırdıktan sonra kilitle (LockMode.NONE) (geçerli örneği eklemek için (merge () ile döndürülen değil) geçerli) bazı kullanım durumlarında işe yarar.


0

Mülkiyet hibernate.allow_refresh_detached_entitybenim için hile yaptı. Ancak genel bir kuraldır, bu yüzden sadece bazı durumlarda yapmak istiyorsanız çok uygun değildir. Umut ediyorum bu yardım eder.

Hazırda Bekletme 5.4.9'da test edildi

SessionFactoryOptionsBuilder



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.