Hazırda Beklet'i kullanarak nesneyi kaydettiğimde aşağıdaki hatayı alıyorum
object references an unsaved transient instance - save the transient instance before flushing
Hazırda Beklet'i kullanarak nesneyi kaydettiğimde aşağıdaki hatayı alıyorum
object references an unsaved transient instance - save the transient instance before flushing
Yanıtlar:
Sen içermelidir cascade="all"
(xml kullanılıyorsa) veya cascade=CascadeType.ALL
koleksiyonunuzu haritalama üzerinde (ek açıklamaları kullanılıyorsa).
Bunun nedeni, varlığınızda bir koleksiyonunuzun olması ve bu koleksiyonun veritabanında bulunmayan bir veya daha fazla öğe içermesidir. Yukarıdaki seçenekleri belirterek hazırda bekletme moduna, üst öğelerini kaydederken bunları veritabanına kaydetmesini söylersiniz.
Bu sadece cevap tekrar olabilir inanıyorum, ama sadece açıklığa kavuşturmak için, bunu bir @OneToOne
harita üzerinde de var @OneToMany
. Her iki durumda da, Child
eklediğim nesnenin Parent
henüz veritabanına kaydedilmemiş olmasıydı. Ben eklendiğinde Yani Child
için Parent
, daha sonra kaydedilmiş Parent
, hazırda atar ki "object references an unsaved transient instance - save the transient instance before flushing"
Ebeveyn kaydederken mesajı.
Her iki durumda cascade = {CascadeType.ALL}
da Parent's
referansa ekleme Child
sorunu çözdü. Bu Child
ve Parent
.
Tekrar cevaplar için üzgünüm, sadece millet için daha fazla açıklamak istedim.
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
new MyEntity
, senkronize edilmiş örneğini veritabanından almak yerine (veritabanıyla senkronize etmeden - yıkama) ile oluşturdunuz. Bu örneği kullanarak Hazırda Bekletme sorguları yapmak, veritabanında olmasını beklediğiniz şeyin, uygulamanızın belleğinde bulunanlardan farklı olduğunu bildirir. Bu durumda, basitçe senkronize edin / varlık veritabanınızı DB'den alın ve kullanın. O zaman hiçbir CascadeType.ALL gerekmez.
Bu, Hazırda Bekletme, kaydettiğiniz nesne ile ilişkili bir nesneyi kaydetmesi gerektiğini düşündüğünde bir nesneyi kaydederken olur.
Bu sorun vardı ve basamaklı türü YOK olmasını istedim bu nedenle başvurulan nesneye değişiklikleri kaydetmek istemiyordu.
Hile, başvurulan nesnedeki ID ve VERSION öğelerinin, Hazırda Bekletme'nin başvurulan nesnenin kaydetme gerektiren yeni bir nesne olduğunu düşünmemesi için ayarlanmasını sağlamaktır. Bu benim için çalıştı.
İlişkili nesneleri (ve ilişkili nesnelerin ilişkili nesnelerini) çözmek için kaydettiğiniz sınıftaki tüm ilişkilere bakın ve ID ve VERSION öğelerinin nesne ağacının tüm nesnelerinde ayarlandığından emin olun.
JPA ve Hibernate kullanırken bu makalede açıkladığım gibi , bir varlık aşağıdaki 4 durumdan birinde olabilir:
Yeni - Bir Hazırda Bekletme Oturumu (Kalıcılık Bağlamı olarak da bilinir) ile ilişkilendirilmemiş olan ve herhangi bir veritabanı tablosu satırıyla eşlenmemiş yeni oluşturulan bir nesne Yeni veya Geçici durumda olarak kabul edilir.
Kalıcı olmak için ya persist
yöntemi açıkça çağırmamız ya da geçişli kalıcılık mekanizmasını kullanmamız gerekir.
Kalıcı - Kalıcı bir varlık, bir veritabanı tablosu satırıyla ilişkilendirilmiştir ve şu anda çalışan Kalıcılık Bağlamı tarafından yönetilmektedir.
Böyle bir kuruluşta yapılan herhangi bir değişiklik tespit edilecek ve veritabanına yayılacaktır (Oturum boşaltma süresi boyunca).
Ayrılmış - Çalışmakta olan Kalıcılık Bağlamı kapatıldıktan sonra, ö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şmeyecek.
Kaldırıldı - JPA yalnızca yönetilen varlıkların kaldırılmasına izin verilmesine rağmen, Hazırda Beklet ayrıca ayrılmış varlıkları da silebilir (ancak yalnızca bir remove
yöntem çağrısı aracılığıyla ).
Bir varlığı bir durumdan diğerine taşımak için persist
, remove
veya merge
yöntemlerini kullanabilirsiniz.
Sorunuzda açıkladığınız sorun:
object references an unsaved transient instance - save the transient instance before flushing
, Yeni durumundaki bir işletmeyi Yönetilen durumdaki bir kuruluşla ilişkilendirmekten kaynaklanır .
Bu, bir alt varlığı üst varlıktaki bire çok koleksiyonuyla ilişkilendirdiğinizde ve koleksiyon cascade
varlık durumu geçişlerini gerçekleştirmediğinde ortaya çıkabilir .
Bu nedenle, bu makalede açıkladığım gibi , bu hatayı tetikleyen varlık derneğine aşağıdaki gibi kademeli ekleyerek bunu düzeltebilirsiniz:
@OneToOne
birleşme@OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
Özellik
CascadeType.ALL
için eklediğimiz değere dikkat edincascade
.
@OneToMany
birleşme@OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
Yine, çift yönlü birleşmeler CascadeType.ALL
için uygundur .@OneToMany
Şimdi, kaskatın çift yönlü olarak düzgün çalışması için, üst ve alt derneklerin senkronize olduğundan emin olmanız gerekir.
Bu hedefe ulaşmanın en iyi yolu hakkında daha fazla bilgi için bu makaleye göz atın .
@ManyToMany
birleşme@ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
Bir @ManyToMany
ilişkilendirmede, silme varlık durumu geçişini bir üst öğeden başka bir üst öğeye yayacağından CascadeType.ALL
veya kullanamazsınız orphanRemoval
.
Bu nedenle, @ManyToMany
ilişkilendirmeler için genellikle CascadeType.PERSIST
veya CascadeType.MERGE
işlemlerini kademelendirirsiniz . Alternatif olarak, DETACH
veya öğesini genişletebilirsiniz REFRESH
.
Bir
@ManyToMany
ilişkilendirmeyi haritalamanın en iyi yolu hakkında daha fazla bilgi için bu makaleye de göz atın.
Veya, istediğiniz şeyi elde etmek için minimum "güçler" kullanmak istiyorsanız (örn. Bir basamaklı silme istemiyorsanız),
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
@ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})
(KALDIR hariç tümü), Hazırda Beklet'in yaptığı gibi güncelleştirmeleri basamaklandırmaz CascadeType.SAVE_UPDATE
.
Benim durumumda bu olmamasından kaynaklandığı CascadeType
üzerinde @ManyToOne
çift yönlü ilişkinin tarafı. Daha kesin olmak gerekirse, ben vardı CascadeType.ALL
üzerinde @OneToMany
yan ve onu yoktu @ManyToOne
. Ekleme CascadeType.ALL
için @ManyToOne
düzeltilen sorunun.
Bire çok tarafı:
@OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
Bire bir taraf (soruna neden oldu)
@ManyToOne
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Çoktan bire (ekleyerek düzeltildi CascadeType.PERSIST
)
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Bu benim için veritabanındaki varolan kaydın @Version (açıklamalı iyimser kilitleme için) açıklamalı alanı için NULL değerine sahip olduğu bir varlık devam ederken meydana geldi. Veritabanında NULL değerini 0 olarak güncelleştirmek bu sorunu düzeltti.
Hatanın tek nedeni bu değil. Ben sadece şimdi kod kaydedilmiş bir yazım hatası hatasıyla karşılaştım, inanıyorum ki, zaten kaydedilmiş bir varlığın değerini ayarlayın.
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
Tam olarak hangi değişkenin hataya neden olduğunu bularak hatayı fark ettim (bu durumda String xid
). catch
Varlığı kurtaran ve izleri basan tüm kod bloğunu kullandım .
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
Cascade.All
Gerçekten gerekene kadar kullanmayın . Role
ve Permission
çift yönlü bir manyToMany
ilişkiye sahiptir. Sonra aşağıdaki kod iyi çalışır
Permission p = new Permission();
p.setName("help");
Permission p2 = new Permission();
p2.setName("self_info");
p = (Permission)crudRepository.save(p); // returned p has id filled in.
p2 = (Permission)crudRepository.save(p2); // so does p2.
Role role = new Role();
role.setAvailable(true);
role.setDescription("a test role");
role.setRole("admin");
List<Permission> pList = new ArrayList<Permission>();
pList.add(p);
pList.add(p2);
role.setPermissions(pList);
crudRepository.save(role);
nesne sadece "yeni" bir nesne ise, o zaman aynı hatayı atar.
Koleksiyonunuz geçersiz ise sadece deneyin: object.SetYouColection(null);
2 sent eklemek için, yanlışlıkla null
kimlik olarak gönderdiğimde aynı sorunu aldım . Aşağıdaki kod benim senaryomu gösteriyor (ve OP herhangi bir senaryodan bahsetmedi) .
Employee emp = new Employee();
emp.setDept(new Dept(deptId)); // --> when deptId PKID is null, same error will be thrown
// calls to other setters...
em.persist(emp);
Burada, yeni bir çalışan örneğine mevcut departman kimliğini, departman varlığını ilk almadan almadan ayarlıyorum, çünkü başka bir seçme sorgusunu tetiklemek istemiyorum.
Bazı senaryolarda, deptId
PKID null
çağırma yönteminden geliyor ve aynı hatayı alıyorum.
null
PK Kimliği değerlerine dikkat edin
Ben işaretli bir yöntemde yeni bir varlık ve ilişkili bir varlık oluşturduktan @Transactional
sonra kaydetmeden önce bir sorgu gerçekleştirdiğimde bu sorun başıma geldi . eski
@Transactional
public someService() {
Entity someEntity = new Entity();
AssocaiatedEntity associatedEntity = new AssocaitedEntity();
someEntity.setAssociatedEntity(associatedEntity);
associatedEntity.setEntity(someEntity);
// Performing any query was causing hibernate to attempt to persist the new entity. It would then throw an exception
someDao.getSomething();
entityDao.create(someEntity);
}
Düzeltmek için, yeni varlık oluşturmadan önce sorguyu gerçekleştirdim.
diğer tüm iyi yanıtların yanı sıra, merge
bir nesneyi devam ettirmek ve yanlışlıkla üst sınıftaki nesnenin birleştirilmiş referansını kullanmayı unutursanız bu gerçekleşebilir . aşağıdaki örneği düşünün
merge(A);
B.setA(A);
persist(B);
Bu durumda, birleştirilir A
ancak öğesinin birleştirilmiş nesnesini kullanmayı unutursunuz A
. sorunu çözmek için kodu bu şekilde yeniden yazmalısınız.
A=merge(A);//difference is here
B.setA(A);
persist(B);
Ben de aynı durumla karşılaştım. Özelliğin üzerinde aşağıdaki ek açıklamayı ayarlayarak, istenen istisnayı çözmesini sağladı.
Karşılaştığım İstisna.
Exception in thread "main" java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.model.Car_OneToMany
Üstesinden gelmek için kullandığım ek açıklama.
@OneToMany(cascade = {CascadeType.ALL})
@Column(name = "ListOfCarsDrivenByDriver")
private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();
Hazırda Bekletme durumunu istisna haline getiren şey:
Üst nesneye eklediğim alt nesne, o anda veritabanında bulunmadığından, bu özel durum konsolunuza atılır.
Sağlayarak @OneToMany(cascade = {CascadeType.ALL})
, Hazırda Beklet'e üst nesneyi kaydederken bunları veritabanına kaydetmesini söyler.
Bütünlük uğruna: A
org.hibernate.TransientPropertyValueException
mesajla
object references an unsaved transient instance - save the transient instance before flushing
Eğer / inat edilecek olur başka bir varlık için bir referans olan bir varlık birleştirmeye çalıştığınızda da ortaya çıkar müstakil .
Başka bir olası neden: Benim durumumda, ebeveyni yepyeni bir varlığa kaydetmeden önce çocuğu kurtarmaya çalışıyordum.
Kod bir User.java modelinde şöyle bir şeydi:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
SetNewPassword () yöntemi bir PasswordHistory kaydı oluşturur ve bunu Kullanıcı'daki geçmiş koleksiyonuna ekler. Create () ifadesi henüz üst öğe için yürütülmediğinden, henüz oluşturulmamış bir varlığın koleksiyonuna kaydetmeye çalışıyordu. Bunu düzeltmek için tek yapmam gereken setNewPassword () çağrısını create () çağrısından sonra taşımaktı.
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
Hazırda bekletme modunda bu hataya neden olabilecek başka bir olasılık daha vardır. A
Ekli bir varlığa nesnenizin kaydedilmemiş bir başvurusunu ayarlayabilir ve nesneyi sürdürmek B
isteyebilirsiniz C
. Bu durumda bile, yukarıda belirtilen hatayı alırsınız.
Bence henüz kalıcı olmayan başka bir nesneye referans olan bir nesneyi ısıtmaya çalıştınız ve bu yüzden "DB tarafında" var olmayan bir satıra bir başvuru koymak deneyin
Bu sorunu çözmenin basit yolu her iki varlığı da kurtarmaktır. önce alt varlığı kaydedin ve sonra ana varlığı kaydedin. Çünkü ana varlık yabancı anahtar değeri için alt varlığa bağımlıdır.
Bire bir ilişkinin basit sınavının altında
insert into Department (name, numOfemp, Depno) values (?, ?, ?)
Hibernate: insert into Employee (SSN, dep_Depno, firstName, lastName, middleName, empno) values (?, ?, ?, ?, ?, ?)
Session session=sf.openSession();
session.beginTransaction();
session.save(dep);
session.save(emp);
Hatanın olası bir nedeni, ana varlığın değerinin ayarlanmasının olmamasıdır; örneğin bir departman-çalışan ilişkisi için hatayı düzeltmek için bunu yazmanız gerekir:
Department dept = (Department)session.load(Department.class, dept_code); // dept_code is from the jsp form which you get in the controller with @RequestParam String department
employee.setDepartment(dept);
Bu hatanın pek çok olasılığı var, diğer olasılıklar da sayfa ekle veya düzenle sayfasında. Benim durumumda bir nesneyi AdvanceSalary kaydetmeye çalışıyordum. Sorun AdvanceSalary edit.loyeloye_employee_id null düzenlemesidir çünkü düzenleme üzerinde ben worker.employee_id ayarlanmadı çünkü. Gizli bir alan yaptım ve ayarladım. kodum kesinlikle iyi çalışıyor.
@Entity(name = "ic_advance_salary")
@Table(name = "ic_advance_salary")
public class AdvanceSalary extends BaseDO{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "employee_id", nullable = false)
private Employee employee;
@Column(name = "employee_id", insertable=false, updatable=false)
@NotNull(message="Please enter employee Id")
private Long employee_id;
@Column(name = "advance_date")
@DateTimeFormat(pattern = "dd-MMM-yyyy")
@NotNull(message="Please enter advance date")
private Date advance_date;
@Column(name = "amount")
@NotNull(message="Please enter Paid Amount")
private Double amount;
@Column(name = "cheque_date")
@DateTimeFormat(pattern = "dd-MMM-yyyy")
private Date cheque_date;
@Column(name = "cheque_no")
private String cheque_no;
@Column(name = "remarks")
private String remarks;
public AdvanceSalary() {
}
public AdvanceSalary(Integer advance_salary_id) {
this.id = advance_salary_id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Long getEmployee_id() {
return employee_id;
}
public void setEmployee_id(Long employee_id) {
this.employee_id = employee_id;
}
}
Ebeveyn nesnesini sürdürmediğim halde çocuğu kurtarırken bu istisna ile karşılaştım. Sorunu çözmek için, aynı oturumda hem alt nesneyi hem de üst nesnelere devam ettim ve üst öğe üzerinde CascadeType.ALL kullandım.
Durum 1: Bir üst öğe oluşturmaya çalışırken ve bu üst öğeyi alt öğeye ve sonra başka bir DELETE / UPDATE sorgusuna (JPQL) kaydetmeye çalışırken bu özel durumu alıyordum. Bu yüzden sadece yeni oluşturulan varlığı ebeveyn oluşturduktan sonra ve aynı ebeveyn referansını kullanarak çocuk oluşturduktan sonra temizlerim. Benim için çalıştı.
Durum 2:
Ebeveyn sınıfı
public class Reference implements Serializable {
@Id
@Column(precision=20, scale=0)
private BigInteger id;
@Temporal(TemporalType.TIMESTAMP)
private Date modifiedOn;
@OneToOne(mappedBy="reference")
private ReferenceAdditionalDetails refAddDetails;
.
.
.
}
Çocuk Sınıfı:
public class ReferenceAdditionalDetails implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@OneToOne
@JoinColumn(name="reference",referencedColumnName="id")
private Reference reference;
private String preferedSector1;
private String preferedSector2;
.
.
}
Yukarıdaki durumda, OneToOne ilişkisine sahip üst öğe (Reference) ve child (ReferenceAdditionalDetails) ve Reference varlığı ve sonra alt öğesini (ReferenceAdditionalDetails) oluşturmaya çalıştığınızda, size aynı istisnayı verecektir. Bu nedenle, istisnayı önlemek için alt sınıf için null değeri ayarlamanız ve sonra üst öğeyi oluşturmanız gerekir. (Örnek Kod)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
Benim sorunum @BeforeEach
JUnit ile ilgiliydi . Ve ilgili varlıkları kurtarsam bile (benim durumumda)@ManyToOne
) kurtarsam bile, aynı hatayı aldım.
Sorun bir şekilde ailemdeki diziyle ilgili. Bu özniteliğe değer atarsam, sorun çözülür.
Ör. Bazı kategoriler (bir veya daha fazla) olabilir varlık soru varsa ve varlık soru bir sırası var:
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedbackSeq")
@Id
private Long id;
Değeri atamam gerekiyor question.setId(1L);
Temel sınıfınızda eşlemenizin Oluşturucusunu yapın. Varlık A'da Bire Bir ilişki istiyorsanız, Varlık B'de A'yı temel sınıf olarak alıyorsanız, A'nın bir Yapıcı'nın B'yi bağımsız değişken olarak alması gerekir.