अफसोस की बात है, मुझे लगता है कि यहां केवल एक टेबल रखने में थोड़ा अंतर है।
PhoneId
. की घोषणा को देखें वर्ग (जो मैं सुझाव दूंगा बेहतर है PhoneOwner
. कहा जाता है या ऐसा ही कुछ):
@Entity
@Table(name="Phones")
public class PhoneId {
जब आप घोषणा करते हैं कि एक वर्ग एक निश्चित तालिका में मैप की गई एक इकाई है, तो आप दावे का एक सेट बना रहे हैं, जिनमें से दो यहां विशेष रूप से महत्वपूर्ण हैं। सबसे पहले, कि इकाई के प्रत्येक उदाहरण के लिए तालिका में एक पंक्ति है, और इसके विपरीत। दूसरे, कि इकाई के प्रत्येक अदिश क्षेत्र के लिए तालिका में एक स्तंभ है, और इसके विपरीत। ये दोनों ही ऑब्जेक्ट-रिलेशनल मैपिंग के विचार के केंद्र में हैं।
हालाँकि, आपकी स्कीमा में, इनमें से कोई भी दावा नहीं है। आपके द्वारा दिए गए डेटा में:
OWNER_ID TYPE NUMBER
1 home 792-0001
1 work 494-1234
2 work 892-0005
owner_id
. वाली इकाई से संबंधित दो पंक्तियाँ हैं 1, पहले दावे का उल्लंघन। कॉलम हैं TYPE
और NUMBER
जो दूसरे अभिकथन का उल्लंघन करते हुए, इकाई में फ़ील्ड के लिए मैप नहीं किए गए हैं।
(स्पष्ट होने के लिए, Phone
. की आपकी घोषणा में कुछ भी गलत नहीं है कक्षा या Phone
फ़ील्ड - बस PhoneId
इकाई)
परिणामस्वरूप, जब आपका जेपीए प्रदाता PhoneId
. का एक उदाहरण सम्मिलित करने का प्रयास करता है डेटाबेस में, यह मुसीबत में चला जाता है। क्योंकि TYPE
. के लिए कोई मैपिंग नहीं है और NUMBER
PhoneId
. में कॉलम , जब यह सम्मिलित करने के लिए SQL उत्पन्न करता है, तो इसमें उनके लिए मान शामिल नहीं होते हैं। यही कारण है कि आपको वह त्रुटि दिखाई देती है जो आपको दिखाई देती है - प्रदाता INSERT INTO Phones (owner_id) VALUES (?)
लिखता है। , जिसे PostgreSQL INSERT INTO Phones (owner_id, type, number) VALUES (?, null, null)
के रूप में मानता है। , जिसे अस्वीकृत कर दिया गया है।
यहां तक कि अगर आपने इस तालिका में एक पंक्ति सम्मिलित करने का प्रबंधन किया है, तब भी आप किसी वस्तु को पुनः प्राप्त करने में परेशानी में पड़ेंगे। मान लें कि आपने PhoneId
. का उदाहरण मांगा है owner_id
. के साथ 1. प्रदाता उन फ़ोनों से select * from Phones where owner_id = 1
, और यह उम्मीद करेगा कि ठीक एक पंक्ति खोजने के लिए, जिसे वह किसी ऑब्जेक्ट पर मैप कर सकता है। लेकिन उसे दो पंक्तियाँ मिलेंगी!
समाधान, मुझे डर है, दो तालिकाओं का उपयोग करना है, एक PhoneId
. के लिए , और एक Phone
. के लिए . PhoneId
. के लिए तालिका मामूली रूप से सरल होगा, लेकिन जेपीए मशीनरी के सही संचालन के लिए यह आवश्यक है।
मान लें कि आप PhoneId
का नाम बदलते हैं PhoneOwner
. को , तालिकाओं को इस तरह दिखना चाहिए:
create table PhoneOwner (
owner_id integer primary key
)
create table Phone (
owner_id integer not null references PhoneOwner,
type varchar(255) not null,
number varchar(255) not null,
primary key (owner_id, number)
)
(मैंने (owner_id, number)
बनाया है Phone
. के लिए प्राथमिक कुंजी , इस धारणा पर कि एक मालिक के पास किसी दिए गए प्रकार की एक से अधिक संख्याएँ हो सकती हैं, लेकिन दो प्रकारों के अंतर्गत एक संख्या कभी दर्ज नहीं होगी। आप (owner_id, type)
prefer पसंद कर सकते हैं अगर वह आपके डोमेन को बेहतर ढंग से दर्शाता है।)
तब संस्थाएं हैं:
@Entity
@Table(name="PhoneOwner")
public class PhoneOwner {
@Id
@Column(name="owner_id")
long id;
@ElementCollection
@CollectionTable(name = "Phone", joinColumns = @JoinColumn(name = "owner_id"))
List<Phone> phones = new ArrayList<Phone>();
}
@Embeddable
class Phone {
@Column(name="type", nullable = false)
String type;
@Column(name="number", nullable = false)
String number;
}
अब, यदि आप वास्तव में PhoneOwner
. के लिए तालिका प्रस्तुत नहीं करना चाहते हैं , तो आप एक दृश्य का उपयोग करके इससे बाहर निकलने में सक्षम हो सकते हैं। इस तरह:
create view PhoneOwner as select distinct owner_id from Phone;
जहां तक जेपीए प्रदाता बता सकता है, यह एक तालिका है, और यह डेटा को पढ़ने के लिए आवश्यक प्रश्नों का समर्थन करेगी।
हालांकि, यह आवेषण का समर्थन नहीं करेगा। यदि आपको किसी ऐसे स्वामी के लिए फ़ोन जोड़ने की आवश्यकता है जो वर्तमान में डेटाबेस में नहीं है, तो आपको पीछे की ओर जाना होगा और सीधे Phone
में एक पंक्ति सम्मिलित करनी होगी . बहुत अच्छा नहीं है।