हाइबरनेट का उपयोग करके ऑब्जेक्ट को सहेजते समय मुझे निम्नलिखित त्रुटि प्राप्त होती है
object references an unsaved transient instance - save the transient instance before flushing
हाइबरनेट का उपयोग करके ऑब्जेक्ट को सहेजते समय मुझे निम्नलिखित त्रुटि प्राप्त होती है
object references an unsaved transient instance - save the transient instance before flushing
जवाबों:
आपको अपने संग्रह मानचित्रण पर (यदि cascade="all"
xml का उपयोग करके) या cascade=CascadeType.ALL
(यदि एनोटेशन का उपयोग करके ) शामिल करना चाहिए ।
ऐसा इसलिए होता है क्योंकि आपके पास अपनी इकाई में एक संग्रह है, और उस संग्रह में एक या अधिक आइटम हैं जो डेटाबेस में मौजूद नहीं हैं। उपरोक्त विकल्पों को निर्दिष्ट करके आप अपने माता-पिता को बचाने के लिए उन्हें डेटाबेस में सहेजने के लिए हाइबरनेट बताते हैं।
मेरा मानना है कि यह केवल उत्तर दोहराने के लिए हो सकता है, लेकिन सिर्फ स्पष्ट करने के लिए, मैंने इसे @OneToOne
मैपिंग पर और साथ ही ए @OneToMany
। दोनों ही मामलों में, यह तथ्य था कि जिस Child
ऑब्जेक्ट को मैं जोड़ रहा था Parent
वह अभी तक डेटाबेस में सहेजा नहीं गया था। तो जब मैं जोड़ा Child
करने के लिए Parent
, तो बचा लिया Parent
, हाइबरनेट टॉस होगा "object references an unsaved transient instance - save the transient instance before flushing"
संदेश जब जनक बचत।
दोनों मामलों में हल की गई समस्या cascade = {CascadeType.ALL}
के Parent's
संदर्भ में जोड़ना Child
। इससे Child
और बच गया Parent
।
किसी भी दोहराने के जवाब के लिए क्षमा करें, बस लोगों के लिए और अधिक स्पष्ट करना चाहता था।
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
new MyEntity
को डेटाबेस से इसके सिंक्रनाइज़ उदाहरण प्राप्त करने के बजाय, डेटाबेस में इसे (फ्लशिंग के बिना सिंक्रनाइज़ किए बिना) बनाया है। उस उदाहरण का उपयोग करके हाइबरनेट प्रश्नों को बनाना आपको सूचित करता है कि डेटाबेस में आपकी जो अपेक्षा है, वह आपके ऐप की मेमोरी में मौजूद चीज़ों से भिन्न है। इस स्थिति में - बस अपनी इकाई को DB से सिंक्रनाइज़ करें / प्राप्त करें और इसका उपयोग करें। कोई CascadeType.ALL तब की जरूरत है।
ऐसा तब होता है जब किसी वस्तु को सहेजते समय हाइबरनेट सोचता है कि उसे उस वस्तु को बचाने की जरूरत है जो आप बचत कर रहे हैं।
मुझे यह समस्या थी और संदर्भित ऑब्जेक्ट में परिवर्तन सहेजना नहीं चाहिए था, इसलिए मैं चाहता था कि झरना प्रकार कोई भी हो।
चाल यह सुनिश्चित करने के लिए है कि संदर्भित ऑब्जेक्ट में आईडी और संस्करण सेट है ताकि हाइबरनेट यह न सोचें कि संदर्भित ऑब्जेक्ट एक नई वस्तु है जिसे सहेजने की आवश्यकता है। इसने मेरे लिए काम किया।
कक्षा में उन सभी रिश्तों के माध्यम से देखें जिन्हें आप संबंधित वस्तुओं (और संबंधित वस्तुओं की संबंधित वस्तुओं) को बाहर निकालने के लिए सहेज रहे हैं और यह सुनिश्चित करते हैं कि आईडी और संस्करण ऑब्जेक्ट ट्री के सभी ऑब्जेक्ट्स में सेट है।
जेपीए और हाइबरनेट का उपयोग करते समय जैसा कि मैंने इस लेख में बताया , एक इकाई निम्नलिखित 4 राज्यों में से एक में हो सकती है:
नई - एक नई बनाई गई वस्तु जो कभी भी एक हाइबरनेट सत्र (उर्फ परसेंटेज कॉन्सेप्ट) से जुड़ी नहीं है और किसी भी डेटाबेस टेबल पंक्ति में मैप नहीं की जाती है जिसे न्यू या ट्रांसिएंट अवस्था में माना जाता है।
लगातार बने रहने के लिए हमें या तो स्पष्ट रूप से persist
विधि को बुलाना होगा या सकर्मक दृढ़ता तंत्र का उपयोग करना होगा।
स्थायी - एक स्थायी इकाई को डेटाबेस तालिका पंक्ति के साथ जोड़ा गया है और यह वर्तमान में चल रहे परिप्रेक्ष्य द्वारा प्रबंधित किया जा रहा है।
ऐसी इकाई में किए गए किसी भी परिवर्तन को डेटाबेस में (सत्र फ्लश-टाइम के दौरान) पहचाना और प्रचारित किया जा रहा है।
अलग किया गया - एक बार वर्तमान में चल रहे परिप्रेक्ष्य को बंद कर दिया जाता है, सभी पहले से प्रबंधित निकाले गए अलग हो जाते हैं। क्रमिक परिवर्तनों को अब ट्रैक नहीं किया जाएगा और कोई स्वचालित डेटाबेस सिंक्रनाइज़ेशन नहीं होने वाला है।
हटाए गए - हालांकि जेपीए मांग करता है कि प्रबंधित इकाइयां केवल हटाने की अनुमति है, हाइबरनेट भी अलग-अलग संस्थाओं को हटा सकता है (लेकिन केवल एक remove
विधि कॉल के माध्यम से )।
एक राज्य से दूसरे के लिए एक इकाई को स्थानांतरित करने के लिए, आप उपयोग कर सकते हैं persist
, remove
या merge
तरीकों।
आप अपने प्रश्न में जिस समस्या का वर्णन कर रहे हैं:
object references an unsaved transient instance - save the transient instance before flushing
नई के राज्य में एक इकाई को प्रबंधित करने की एक इकाई के कारण होता है जो प्रबंधित की स्थिति में होती है ।
यह तब हो सकता है जब आप चाइल्ड एंटिटी को पैरेंट एंटिटी में एक-से-कई संग्रह में जोड़ रहे हों, और यह संग्रह cascade
यूनिट स्टेट ट्रांज़िशन नहीं करता है ।
इसलिए, जैसा कि मैंने इस लेख में बताया है , आप इस विफलता को ट्रिगर करने वाली संस्था एसोसिएशन में कैस्केड जोड़कर इसे ठीक कर सकते हैं, जैसे कि:
@OneToOne
संगति@OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
विशेषता के
CascadeType.ALL
लिए हमने जो मूल्य जोड़ा है, उस पर ध्यान देंcascade
।
@OneToMany
संगति@OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
फिर, द्विदिश संघों CascadeType.ALL
के लिए उपयुक्त है ।@OneToMany
अब, कैस्केड के लिए एक द्विदिश में ठीक से काम करने के लिए, आपको यह भी सुनिश्चित करने की आवश्यकता है कि माता-पिता और बच्चे के संगठन सिंक में हैं।
की जाँच करें इस लेख का सबसे अच्छा तरीका इस लक्ष्य को प्राप्त करने के लिए है के बारे में अधिक जानकारी के लिए।
@ManyToMany
संगति@ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
एक @ManyToMany
संघ में, आप उपयोग नहीं कर सकते हैं CascadeType.ALL
या orphanRemoval
इस तरह से डिलीट एंटिटी स्टेट ट्रांजेक्शन को एक पैरेंट से दूसरे पैरेंट यूनिट में बदल देगा।
इसलिए, @ManyToMany
संघों के लिए, आप आमतौर पर CascadeType.PERSIST
या CascadeType.MERGE
संचालन को रोकते हैं । वैकल्पिक रूप से, आप इसका विस्तार कर सकते हैं DETACH
या कर सकते हैं REFRESH
।
किसी
@ManyToMany
एसोसिएशन को मैप करने के सर्वोत्तम तरीके के बारे में अधिक जानकारी के लिए , इस लेख को भी देखें।
या, यदि आप कम से कम "शक्तियों" का उपयोग करना चाहते हैं (जैसे कि यदि आप कैस्केड हटाना नहीं चाहते हैं) तो आप जो चाहते हैं उसे प्राप्त करने के लिए उपयोग करें
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
@ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})
(सभी लेकिन REMOVE) हाइबरनेट की तरह अपडेट को कैस्केड नहीं CascadeType.SAVE_UPDATE
करता है।
मेरे मामले में यह द्विदिश संबंध CascadeType
के @ManyToOne
पक्ष में नहीं होने के कारण हुआ था । अधिक सटीक होना, मैं था CascadeType.ALL
पर @OneToMany
पक्ष और उस पर नहीं था @ManyToOne
। मुद्दे CascadeType.ALL
को @ManyToOne
हल करने के लिए जोड़ना ।
एक से कई पक्ष:
@OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
कई-एक तरफ (समस्या के कारण)
@ManyToOne
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
कई-से-एक (जोड़कर तय CascadeType.PERSIST
)
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
यह मेरे लिए तब हुआ जब एक इकाई को बनाए रखने के लिए जिसमें डेटाबेस में मौजूदा रिकॉर्ड @Version (आशावादी लॉकिंग के लिए) के साथ एनोटेट किए गए फ़ील्ड के लिए एक पूर्ण मान था। डेटाबेस में NULL मान को 0 में अद्यतन करने से यह ठीक हो गया।
यह त्रुटि का एकमात्र कारण नहीं है। मैंने अभी-अभी अपने कोडिंग में एक टाइपो त्रुटि के लिए सामना किया, जो मुझे विश्वास है, एक इकाई का मान सेट करें जो पहले से ही सहेजा गया था।
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
मैंने त्रुटि का पता लगा लिया कि कौन सा चर त्रुटि का कारण बना (इस मामले में String xid
)। मैंने catch
कोड के पूरे ब्लॉक का उपयोग किया जिसने इकाई को बचाया और निशान मुद्रित किया।
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
Cascade.All
तब तक उपयोग न करें जब तक आपको वास्तव में नहीं करना है। Role
और Permission
द्विदिश manyToMany
संबंध है। फिर निम्न कोड ठीक काम करेगा
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);
जबकि अगर वस्तु सिर्फ एक "नया" है, तो यह उसी त्रुटि को फेंक देगा।
यदि आपका संग्रह अशक्त है, तो बस कोशिश करें: object.SetYouColection(null);
अपने 2 सेंट जोड़ने के लिए, मुझे यह वही मुद्दा मिला जब मैं गलती null
से आईडी के रूप में भेज रहा हूं । नीचे दिए गए कोड में मेरे परिदृश्य को दर्शाया गया है (और ओपी ने किसी विशिष्ट परिदृश्य का उल्लेख नहीं किया है) ।
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);
यहां मैं मौजूदा डिपार्टमेंट आईडी को एक नए कर्मचारी उदाहरण में स्थापित कर रहा हूं, वास्तव में विभाग की इकाई को पहले प्राप्त किए बिना, क्योंकि मैं आग के लिए किसी अन्य प्रश्न का चयन नहीं करना चाहता।
कुछ परिदृश्यों में, कॉलिंग विधि से deptId
PKID आ null
रहा है और मुझे वही त्रुटि मिल रही है।
तो, null
पीके आईडी के लिए मान देखें
यह समस्या मेरे साथ तब हुई जब मैंने एक नई इकाई और संबंधित इकाई को एक विधि के रूप में चिह्नित किया @Transactional
, फिर बचत करने से पहले एक क्वेरी की। भूतपूर्व
@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);
}
ठीक करने के लिए, मैंने नई इकाई बनाने से पहले क्वेरी का प्रदर्शन किया।
अन्य सभी अच्छे उत्तरों के साथ, यह तब हो सकता है जब आप merge
किसी ऑब्जेक्ट को जारी रखने के लिए उपयोग करते हैं और गलती से मूल वर्ग में ऑब्जेक्ट के मर्ज किए गए संदर्भ का उपयोग करना भूल जाते हैं। निम्नलिखित उदाहरण पर विचार करें
merge(A);
B.setA(A);
persist(B);
इस स्थिति में, आप विलय कर देते हैं A
लेकिन विलय की गई वस्तु का उपयोग करना भूल जाते हैं A
। समस्या को हल करने के लिए आपको इस तरह कोड को फिर से लिखना होगा।
A=merge(A);//difference is here
B.setA(A);
persist(B);
मैंने भी उसी स्थिति का सामना किया। संपत्ति के ऊपर एनोटेशन की स्थापना करके, इससे प्रेरित अपवाद को हल किया जाता है।
अपवाद का सामना करना पड़ा।
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
जिसे दूर करने के लिए मैंने एनोटेशन का इस्तेमाल किया।
@OneToMany(cascade = {CascadeType.ALL})
@Column(name = "ListOfCarsDrivenByDriver")
private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();
हाइबरनेट ने अपवाद को क्या बनाया:
इस अपवाद को आपके कंसोल पर फेंक दिया गया है क्योंकि उस समय मैं मूल ऑब्जेक्ट से संलग्न चाइल्ड ऑब्जेक्ट डेटाबेस में मौजूद नहीं है।
प्रदान करके @OneToMany(cascade = {CascadeType.ALL})
, यह हाइबरनेट को मूल वस्तु को सहेजते समय डेटाबेस में सहेजने के लिए कहता है।
संपूर्णता के लिए: ए
org.hibernate.TransientPropertyValueException
संदेश के साथ
object references an unsaved transient instance - save the transient instance before flushing
तब भी होगा जब आप किसी इकाई को किसी अन्य इकाई के संदर्भ में जारी रखने / मर्ज करने का प्रयास करेंगे, जो अलग होना होता है ।
एक अन्य संभावित कारण: मेरे मामले में, मैं एक नए ब्रांड पर, माता-पिता को बचाने से पहले बच्चे को बचाने का प्रयास कर रहा था।
कोड कुछ इस तरह था User.java मॉडल में:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
SetNewPassword () विधि एक PasswordHistory रिकॉर्ड बनाता है और इसे उपयोगकर्ता में इतिहास संग्रह में जोड़ता है। चूंकि पैरेंट के लिए अभी तक क्रिएट () स्टेटमेंट को निष्पादित नहीं किया गया था, इसलिए यह एक ऐसी इकाई के संग्रह को सहेजने की कोशिश कर रहा था जो अभी तक बनाई नहीं गई थी। इसे ठीक करने के लिए मुझे केवल इतना करना था कि सेटन्यूपासवर्ड () कॉल को कॉल करने के बाद () में ले जाएँ।
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
मुझे लगता है कि क्योंकि आपने एक ऐसी वस्तु को बनाए रखने की कोशिश की है, जिसके पास किसी अन्य वस्तु का संदर्भ है जो अभी तक कायम नहीं है, और इसलिए यह "DB पक्ष" में एक पंक्ति के संदर्भ को रखने की कोशिश करता है जो मौजूद नहीं है
इस मुद्दे को हल करने का सरल तरीका दोनों इकाई को बचाने के लिए है। पहले बाल इकाई को बचाएं और फिर मूल संस्था को बचाएं। क्योंकि मूल इकाई विदेशी कुंजी मूल्य के लिए बाल इकाई पर निर्भर है।
एक से एक संबंधों की सरल परीक्षा
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);
त्रुटि का एक संभावित कारण मूल इकाई के मूल्य की अनिवार्यता है; उदाहरण के लिए विभाग-कर्मचारियों के संबंध में आपको त्रुटि को ठीक करने के लिए यह लिखना होगा:
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);
इस त्रुटि की बहुत सारी संभावनाएं हैं कुछ अन्य संभावनाएं भी ऐड पेज या एडिट पेज पर हैं। मेरे मामले में मैं एक ऑब्जेक्ट एडवांस सैलेरी को बचाने की कोशिश कर रहा था। समस्या यह है कि एडवांस सैलेरी कर्मचारी को संपादित करने में ।employee_id अशक्त है क्योंकि संपादन पर मैंने कर्मचारी को सेट नहीं किया था। Employee_id। मैंने एक छुपा क्षेत्र बनाया है और इसे सेट किया है। मेरा कोड बिल्कुल ठीक काम कर रहा है।
@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;
}
}
मुझे इस अपवाद का सामना करना पड़ा जब मैंने माता-पिता की वस्तु को जारी नहीं रखा, लेकिन मैं बच्चे को बचा रहा था। समस्या को हल करने के लिए, एक ही सत्र में मैंने बच्चे और माता-पिता दोनों वस्तुओं को जारी रखा और माता-पिता पर CascadeType.ALL का उपयोग किया।
केस 1: मुझे यह अपवाद तब मिल रहा था जब मैं एक माता-पिता बनाने की कोशिश कर रहा था और उस माता-पिता के संदर्भ को अपने बच्चे के लिए सहेज रहा था और फिर कुछ अन्य DELETE / अद्यतन क्वेरी (JPQL)। इसलिए मैं सिर्फ अभिभावक बनाने के बाद और उसी अभिभावक संदर्भ का उपयोग करके बच्चा पैदा करने के बाद नव निर्मित इकाई को प्रवाहित करता हूं। इसने मेरे लिए काम किया।
केस 2:
जनक वर्ग
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;
.
.
.
}
बाल वर्ग:
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;
.
.
}
उपरोक्त मामले में जहां माता-पिता (संदर्भ) और बच्चे (ReferenceAdditionalDetails) का OneToOne संबंध है और जब आप संदर्भ इकाई और फिर उसके बच्चे (ReferenceAdditionalDetails) को बनाने का प्रयास करते हैं, तो यह आपको वही अपवाद देगा। इसलिए अपवाद से बचने के लिए आपको बच्चे की कक्षा के लिए अशक्त सेट करना होगा और फिर अभिभावक बनाना होगा। (नमूना कोड)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
मेरी समस्या @BeforeEach
JUnit से संबंधित थी । और यहां तक कि अगर मैंने संबंधित संस्थाओं (मेरे मामले में @ManyToOne
) को बचाया, तो भी मुझे वही त्रुटि मिली।
समस्या किसी तरह से उस अनुक्रम से संबंधित है जो मेरे माता-पिता में है। यदि मैं उस विशेषता को मान प्रदान करता हूं, तो समस्या हल हो जाती है।
पूर्व। यदि मेरे पास इकाई प्रश्न है तो कुछ श्रेणियां (एक या अधिक) हो सकती हैं और इकाई प्रश्न में एक अनुक्रम है:
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedbackSeq")
@Id
private Long id;
मुझे मान असाइन करना होगा question.setId(1L);
बस अपने बेस क्लास में अपनी मैपिंग का कंस्ट्रक्टर बनाएं। जैसे अगर आप Entity A, Entity B में One-To-One संबंध चाहते हैं, यदि आपका आधार वर्ग के रूप में A ले रहा है, तो A के पास एक तर्क के रूप में B का एक कन्स्ट्रक्टर होना चाहिए।