वहाँ एक एंटिटी क्लास "ए" है। कक्षा ए में एक ही प्रकार के बच्चे हो सकते हैं "ए"। यदि बच्चा है तो "ए" को उसके माता-पिता को पकड़ना चाहिए।
क्या यह संभव है? यदि हां, तो मुझे इकाई वर्ग में संबंधों को कैसे मैप करना चाहिए? ["A" में एक आईडी कॉलम है।]
जवाबों:
हां, यह संभव है। यह मानक द्विदिश @ManyToOne
/ @OneToMany
संबंध का एक विशेष मामला है । यह विशेष है क्योंकि संबंध के प्रत्येक छोर पर इकाई समान है। सामान्य मामला JPA 2.0 कल्पना की धारा 2.10.2 में विस्तृत है ।
यहां एक उदाहरण दिया गया है। सबसे पहले, इकाई वर्ग A
:
@Entity
public class A implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne
private A parent;
@OneToMany(mappedBy="parent")
private Collection<A> children;
// Getters, Setters, serialVersionUID, etc...
}
यहाँ एक कठिन main()
तरीका है जो तीन ऐसी संस्थाओं को बनाए रखता है:
public static void main(String[] args) {
EntityManager em = ... // from EntityManagerFactory, injection, etc.
em.getTransaction().begin();
A parent = new A();
A son = new A();
A daughter = new A();
son.setParent(parent);
daughter.setParent(parent);
parent.setChildren(Arrays.asList(son, daughter));
em.persist(parent);
em.persist(son);
em.persist(daughter);
em.getTransaction().commit();
}
इस मामले में, लेनदेन करने से पहले सभी तीन इकाई उदाहरणों को बरकरार रखा जाना चाहिए। यदि मैं माता-पिता-बच्चे के रिश्तों के ग्राफ में किसी एक संस्था को बनाए रखने में विफल रहता हूं, तो एक अपवाद को फेंक दिया जाता है commit()
। एक्लिप्सिंक पर, यह RollbackException
विसंगति का विवरण है।
यह व्यवहार 's और एनोटेशन cascade
पर विशेषता के माध्यम से विन्यास योग्य है । उदाहरण के लिए, यदि मैं उन दोनों एनोटेशनों पर सेट करता हूं, तो मैं सुरक्षित रूप से किसी एक संस्था को बनाए रख सकता हूं और दूसरों को अनदेखा कर सकता हूं। कहते हैं कि मैं अपने लेन-देन में कायम रहा । जेपीए कार्यान्वयन traverses के संपत्ति है क्योंकि यह के साथ चिह्नित है । जेपीए कार्यान्वयन वहाँ और वहाँ पाता है । यह तब भी मेरी ओर से दोनों बच्चों को जारी रखता है, भले ही मैंने स्पष्ट रूप से इसका अनुरोध न किया हो।A
@OneToMany
@ManyToOne
cascade=CascadeType.ALL
parent
parent
children
CascadeType.ALL
son
daughter
एक और नोट। यह हमेशा प्रोग्रामर की जिम्मेदारी होती है कि वह एक द्विदिश संबंध के दोनों पक्षों को अपडेट करे। दूसरे शब्दों में, जब भी मैं किसी माता-पिता के लिए एक बच्चा जोड़ता हूं, मुझे उसके अनुसार बच्चे की मूल संपत्ति को अपडेट करना चाहिए। एक द्विदिश संबंध के केवल एक पक्ष को अपडेट करना जेपीए के तहत एक त्रुटि है। रिश्ते के दोनों किनारों को हमेशा अपडेट करें। यह JPA 2.0 कल्पना के पृष्ठ 42 पर असंदिग्ध रूप से लिखा गया है:
ध्यान दें कि यह एप्लिकेशन है जो रनटाइम रिश्तों की निरंतरता बनाए रखने के लिए जिम्मेदारी वहन करता है - उदाहरण के लिए, यह सुनिश्चित करने के लिए कि एक द्विदिश संबंध के "एक" और "कई" पक्ष एक दूसरे के साथ संगत हैं जब एप्लिकेशन रनटाइम पर संबंध को अपडेट करता है। ।
मेरे लिए यह ट्रिक कई-कई संबंधों का उपयोग करने के लिए थी। मान लीजिए कि आपकी इकाई A एक ऐसा डिवीजन है जिसमें सब-डिवीजन हो सकते हैं। तब (अप्रासंगिक विवरणों को छोड़ते हुए):
@Entity
@Table(name = "DIVISION")
@EntityListeners( { HierarchyListener.class })
public class Division implements IHierarchyElement {
private Long id;
@Id
@Column(name = "DIV_ID")
public Long getId() {
return id;
}
...
private Division parent;
private List<Division> subDivisions = new ArrayList<Division>();
...
@ManyToOne
@JoinColumn(name = "DIV_PARENT_ID")
public Division getParent() {
return parent;
}
@ManyToMany
@JoinTable(name = "DIVISION", joinColumns = { @JoinColumn(name = "DIV_PARENT_ID") }, inverseJoinColumns = { @JoinColumn(name = "DIV_ID") })
public List<Division> getSubDivisions() {
return subDivisions;
}
...
}
चूँकि मेरे पास पदानुक्रमित संरचना और JPA (रिलेशनल मॉडल के आधार पर) के आसपास कुछ व्यापक व्यावसायिक तर्क थे, इसलिए इसका समर्थन करने के लिए बहुत कमजोर हूं मैंने इंटरफ़ेस IHierarchyElement
और इकाई श्रोता पेश किया HierarchyListener
:
public interface IHierarchyElement {
public String getNodeId();
public IHierarchyElement getParent();
public Short getLevel();
public void setLevel(Short level);
public IHierarchyElement getTop();
public void setTop(IHierarchyElement top);
public String getTreePath();
public void setTreePath(String theTreePath);
}
public class HierarchyListener {
@PrePersist
@PreUpdate
public void setHierarchyAttributes(IHierarchyElement entity) {
final IHierarchyElement parent = entity.getParent();
// set level
if (parent == null) {
entity.setLevel((short) 0);
} else {
if (parent.getLevel() == null) {
throw new PersistenceException("Parent entity must have level defined");
}
if (parent.getLevel() == Short.MAX_VALUE) {
throw new PersistenceException("Maximum number of hierarchy levels reached - please restrict use of parent/level relationship for "
+ entity.getClass());
}
entity.setLevel(Short.valueOf((short) (parent.getLevel().intValue() + 1)));
}
// set top
if (parent == null) {
entity.setTop(entity);
} else {
if (parent.getTop() == null) {
throw new PersistenceException("Parent entity must have top defined");
}
entity.setTop(parent.getTop());
}
// set tree path
try {
if (parent != null) {
String parentTreePath = StringUtils.isNotBlank(parent.getTreePath()) ? parent.getTreePath() : "";
entity.setTreePath(parentTreePath + parent.getNodeId() + ".");
} else {
entity.setTreePath(null);
}
} catch (UnsupportedOperationException uoe) {
LOGGER.warn(uoe);
}
}
}
Top
एक रिश्ता है। JPA 2.0 कल्पना, एंटिटी श्रोताओं और कॉलबैक विधियों के पेज 93: "सामान्य तौर पर, एक पोर्टेबल एप्लिकेशन के जीवनचक्र विधि को एंटिटी मैनजर या क्वेरी संचालन, अन्य इकाई उदाहरणों का उपयोग या रिश्तों को संशोधित नहीं करना चाहिए"। सही? मुझे पता है कि क्या मैं बंद हूँ।