2012-06-15 5 views
9

स्थिति

मैं एक DiscriminatorColumn, एकल तालिका भाग के लिए कॉन्फ़िगर के साथ एक इकाई है:DiscriminatorColumn/आईडी

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="TYPE") 
public class ContainerAssignment{ 
... 
} 

'ContainerAssignment' एक और इकाई के लिए एक संदर्भ है:

@JoinColumn(name="CONTAINER_ID") 
private Container container; 

एक कंटेनर में प्रत्येक प्रकार के ContainerAssignment हो सकते हैं। इसका मतलब है कि ContainerAssignment तालिका की प्राथमिक कुंजी CONTAINER_ID और TYPE द्वारा परिभाषित की गई है।

ContainerAssignment में कुछ उप-वर्ग हैं उदा।

@Entity 
@DiscriminatorValue("SOME_TYPE") 
public class SomeTypeOfContainerAssignment extends ContainerAssignment{ 
... 
} 

वहाँ केवल एक दिया CONTAINER_ID के लिए एक एकल SomeTypeOfContainerAssignment उदाहरण होगा।

समस्या

अगर मैं जेपीए @Id के रूप में सिर्फ कंटेनर को परिभाषित ContainerAssignment मेज पर, मैं जो महान है entityManager.find(SomeTypeOfContainerAssignment.class, containerId) कर सकते हैं। यह SELECT * FROM CONTAINER_ASSIGNMENT WHERE CONTAINER_ID = 1 AND TYPE = 'SOME_TYPE'; की लाइनों के साथ कुछ चलाता है। यह जानता है कि एंटीटी पर @DiscriminatorValue("SOME_TYPE") एनोटेशन की वजह से इसे यहां टाइप प्रकार की जांच की आवश्यकता है।

हालांकि, इसका मतलब यह है कि कंटेनर से कंटेनर एस्सिग्मेंट ब्रेक के पीछे संदर्भ कंटेनर वास्तव में प्राथमिक कुंजी नहीं है। उदाहरण के लिए, यदि कंटेनर में @OneToOne(mappedBy=container) private SomeTypeOfContainerAssignment assignment; है, जब आप किसी कंटेनर में पढ़ते हैं, तो यह टाइपिंग के बिना SELECT * FROM CONTAINER_ASSIGNMENT WHERE CONTAINER_ID = 1; जैसे असाइनमेंट में पढ़ेगा। यह इसे एक कंटेनर के लिए सभी असाइनमेंट देता है, और उसके बाद यह गलत तरीके से यादृच्छिक रूप से यादृच्छिक रूप से चुनता है, इस मामले में, यह एक अपवाद फेंकता है।

यदि इसके बजाय, मैं कंटेनर एस्सिग्मेंटमेंट के जेपीए @Id को कंटेनर और टाइप का उपयोग करके एक समग्र आईडी के रूप में परिभाषित करता हूं, कंटेनर एस्सिग्मेंट वर्क जुर्माना के उप-वर्गों के संदर्भ।

हालांकि, मैं entityManager.find(SomeTypeOfContainerAssignment.class, containerId) नहीं कर सकता, क्योंकि कंटेनर आईडी नहीं है। मुझे entityManager.find(SomeTypeOfContainerAssignment.class, new MyPk(containerId, "SOME_TYPE")) करना है, जो @DiscriminatorValue("SOME_TYPE") के बिंदु को हराने के लिए प्रतीत होता है। अगर मैं किसी भी तरह से खोजने के लिए टाइप निर्दिष्ट करना चाहता हूं तो मैं केवल एक कंटेनर एसिग्मेंट एंटिटी का उपयोग कर सकता हूं।

प्रश्न

वहाँ जहां मेज पर प्राथमिक कुंजी discriminator स्तंभ पर समग्र है, जबकि भी बस द्वारा EntityManager.find करने में सक्षम होने के लिए एक एकल मेज विरासत इकाई के उप-वर्गों के लिए काम कर संदर्भों के लिए एक रास्ता है प्राथमिक कुंजी का हिस्सा जो भेदभावकर्ता नहीं है?

उत्तर

0

तो ContainerSomeTypeOfContainerAssignment के साथ एक द्विदिश OneToOne, जो ContainerAssignment फैली है, तो कंटेनर फ़ील्ड परिभाषित नहीं किया जाना चाहिए और ContainerAssignment में मैप किया है, लेकिन SomeTypeOfContainerAssignment में:

public class Container { 
    @Id 
    private Long id; 

    @OneToOne(mappedBy = "container") 
    private SomeTypeOfContainerAssignment someTypeOfContainerAssignment; 
} 

public class ContainerAssignment { 
    @Id 
    private Long id; 
} 

public class SomeTypeOfContainerAssignment extends ContainerAssignment { 
    @OneToOne 
    private Container container; 
} 

तो सभी कंटेनर कार्य के प्रकार इस तरह के है कंटेनर के साथ एक OneToOne संघ, आप आप एक ही jo उपयोग करने की अनुमति है, तो

public abstract class ContainerAssignment { 
    @Id 
    private Long id; 

    public abstract Container getContainer(); 
    public abstract void setContainer(Container container); 
} 

के रूप में कंटेनर को परिभाषित, ईमानदारी से कहूं तो कर सकते हैं मैं नहीं जानता प्रत्येक उपclass के @OneToOne container क्षेत्रों को मैप करने के लिए तालिका में कॉलम में।

मुझे लगता है कि यह आपके पास सबसे अच्छा है। यदि आप बेस क्लास में कंटेनर फ़ील्ड डालते हैं, तो आपको एसोसिएशन को OneToMany/ManyToOne एसोसिएशन के रूप में परिभाषित करना होगा, क्योंकि यह वास्तव में है।

मुझे नहीं लगता कि आप क्या करना चाहते हैं, और मैं समग्र पीके के साथ गड़बड़ नहीं करता, क्योंकि वे अच्छे कारणों से निराश होते हैं, और उपयोग करने के लिए एक दुःस्वप्न।

+1

आपके उत्तर के लिए धन्यवाद, लेकिन यह वास्तव में प्रश्न को हल नहीं करता है - क्या पीके के अंदर 'DiscriminatorColumn' kinda डालने का कोई तरीका है? मैं मानता हूं कि एक कृत्रिम पीके सबसे अच्छा विकल्प है, लेकिन कई प्रणालियों में हम स्कीमा को नियंत्रित नहीं कर सकते हैं और समग्र पीके से निपटना होगा। –

+0

बिल कार्विन पुस्तक के मुताबिक, समग्र प्राथमिक कुंजी का उपयोग कभी भी विरोधी पैटर्न नहीं है। – atorres

0

मैं यह मानने जा रहा हूं कि कंटेनर एसिग्मेंटमेंट की समग्र प्राथमिक कुंजी ठीक काम कर रही है (मुझे लगता है कि यह जेपीए कार्यान्वयन निर्भर हो सकता है!), और जो भी आपको परेशान करता है वह इकाई के लिए परेशान कॉल है। फाइनर और पीके इन्स्टेन्शियशन।

मेरा समाधान जेपीए एपीआई से स्वतंत्र खोजक विधियों को परिभाषित करना है। खुद को जेपीए में लॉक न करें। सबसे आसान तरीका है कि आप अपने डोमेन क्लास पर एक स्थैतिक खोजक को परिभाषित करें (या, केवल खोजकर्ताओं के साथ एक और कक्षा को परिभाषित करें, यदि आप डोमेन को अनजान करते हुए जेपीए करना चाहते हैं। IoC पर यह पता करने के लिए कि यह कैसे करें)।

ContainerAssignment (या अपने खोजक वर्ग) में:

public static <T extends ContainerAssignment> T findByPK(EntityManager manager,Class<T> type,long id) { 
    DiscriminatorValue val = type.getAnnotation(DiscriminatorValue.class); // this is not optimal...can be cached... 
    return (T) manager.find(type, new MyPk(containerId, val.getValue())); 
} 

अपने कोड में:

SomeTypeOfContainerAssignment ca = ContainerAssignment.findByPK(entityManager,SomeTypeOfContainerAssignment.class,containerId); 

सूचना पी के प्रकार हिस्सा बनाने का मतलब है कि आप अलग से दो ContainerAssignment उदाहरण हो सकते हैं कि एक ही आईडी के साथ प्रकार। यदि आप इसके प्रकार को नहीं जानते हैं तो आपको कंटेनर एसिग्मेंटमेंट पुनर्प्राप्त करने के लिए एक क्वेरी की आवश्यकता होगी। यदि, हालांकि, आपकी आईडी अनुक्रम से उत्पन्न होती है, तो आप केवल एक और खोजक विधि लिख सकते हैं जो आंतरिक ढांचे को आंतरिक ढांचे में छुपाती है, परिणामस्वरूप परिणाम का पहला परिणाम लौटाती है।