2009-01-25 10 views
5

आप NHibernate में किसी पंक्ति के उप प्रकार को बदलने के बारे में कैसे जाते हैं? उदाहरण के लिए यदि मेरे पास ग्राहक इकाई है और TierOneCustomer का उप-वर्ग है, तो मेरे पास एक ऐसा मामला है जहां मुझे ग्राहक को टियरऑन ग्राहक में बदलने की आवश्यकता है लेकिन TierOneCustomer के पास मूल ग्राहक इकाई के समान आईडी (पीके) होना चाहिए।NHibernate - उप-प्रकार बदलना

मानचित्रण इस तरह दिखता है:

<class name="Customer" table="SiteCustomer" discriminator-value="C"> 
    <id name="Id" column="Id" type="Int64"> 
    <generator class="identity" /> 
    </id> 
    <discriminator column="CustomerType" /> 
    ... properties snipped ... 

    <subclass name="TierOneCustomer" discriminator-value="P"> 
    ... more properties ... 
    </subclass> 
</class> 

मैं प्रति वर्ग एक तालिका पदानुक्रम मॉडल का उपयोग कर रहा है, तो सादे एसक्यूएल का उपयोग कर, इसके बारे में एक एसक्यूएल अद्यतन का मामला होगा भेदभावकर्ता (ग्राहक प्रकार) और प्रकार के लिए प्रासंगिक उचित कॉलम सेट करें। मुझे NHibernate में समाधान नहीं मिल रहा है, इसलिए किसी भी पॉइंटर्स की सराहना करेंगे।

मैं यह भी सोच रहा हूं कि मॉडल इस उपयोग के मामले पर सही है या नहीं, लेकिन मैं उस मार्ग से नीचे जाने से पहले, मैं यह सुनिश्चित करना चाहता हूं कि ऊपर वर्णित अनुसार वास्तव में संभव है। यदि नहीं, तो मैं लगभग मॉडल को बदलने के बारे में निश्चित रूप से सोचूंगा।

उत्तर

9

संक्षिप्त उत्तर हाँ है, आप native SQL का उपयोग कर विशेष पंक्ति (ओं) के लिए भेदभाव मूल्य बदल सकते हैं।

हालांकि, मुझे नहीं लगता कि एनएचबीरनेट का उद्देश्य इस तरह से काम करना है, क्योंकि भेदभावकर्ता जावा परत पर आम तौर पर "अदृश्य" होता है, जहां इसका मूल्य प्रारंभिक वस्तु के वर्ग के अनुसार शुरू में रखा जाना चाहिए और कभी बदला नहीं गया।

मैं एक क्लीनर दृष्टिकोण की तलाश करने की सलाह देता हूं। ऑब्जेक्ट मॉडल के दृष्टिकोण से, आप एक सुपरक्लास ऑब्जेक्ट को अपने उप-वर्ग प्रकार में परिवर्तित करने की कोशिश कर रहे हैं, जबकि इसके निरंतर उदाहरण की पहचान नहीं बदल रहे हैं, और जहां वह संघर्ष है (परिवर्तित वस्तु वास्तव में नहीं माना जाता है वही चीज़)। दो वैकल्पिक दृष्टिकोण हैं:

  • मूल ग्राहक ऑब्जेक्ट में जानकारी के आधार पर TierOneCustomer का एक नया उदाहरण बनाएं, फिर मूल ऑब्जेक्ट को हटाएं। यदि आप पुनर्प्राप्ति के लिए ग्राहक की प्राथमिक कुंजी पर भरोसा कर रहे थे, तो आपको नए पीके पर ध्यान देना होगा।

या

  • अपने दृष्टिकोण बदलें ताकि ऑब्जेक्ट प्रकार (discriminator) को बदलने की जरूरत नहीं है। एक उपवर्ग ग्राहक से TierOneCustomer भेद करने के लिए पर भरोसा करने की बजाय, आप एक संपत्ति है कि आप किसी भी समय स्वतंत्र रूप से संशोधित कर सकते हैं, यानी Customer.Tier उपयोग कर सकते हैं = 1.

यहाँ हाइबरनेट मंच पर कुछ संबंधित विचार-विमर्श कर रहे हैं कि हो सकता है रुचि का हो:

  1. Can we update the discriminator column in Hibernate
  2. Table-per-Class Problem: Discriminator and Property
  3. Converting a persisted instance into a subclass
+0

हाँ, मुझे लगता है कि मैं पदानुक्रम को दोबारा शुरू करने जा रहा हूं और शायद साधारण संपत्ति दृष्टिकोण का चयन कर रहा हूं। महान जवाब, धन्यवाद। –

1

यदि आप इसे ऑफ़लाइन कर रहे हैं (उदा। एक डीबी अपग्रेड स्क्रिप्ट में), बस एसक्यूएल का उपयोग करें और खुद को स्थिरता सुनिश्चित करें।

यदि ऐसा कुछ है जो आप ऐप चलते समय करेंगे, तो मुझे लगता है कि आपकी आवश्यकताएं गलत हैं, जैसे कि एक अलग ऑब्जेक्ट के लिए एक ही पॉइंटर पता रखना गलत है।

यदि आप आईडी को सहेजते हैं और फिर से ग्राहक तक पहुंचने के लिए इसका उपयोग करते हैं (उदा। URL में) एक नया फ़ील्ड बनाने पर विचार करें जिसमें इसके लिए एक टोकन है जो व्यवसाय कुंजी होगी। चूंकि यह आईडी नहीं है, इसलिए एक नया इकाई उदाहरण बनाना और टोकन पर प्रतिलिपि बनाना आसान है (आपको शायद पुराने से टोकन को हटाने की आवश्यकता होगी)।

5

आप कुछ गलत कर रहे हैं।

आप जो करने का प्रयास कर रहे हैं वह किसी ऑब्जेक्ट के प्रकार को बदलना है। आप इसे .NET या जावा में नहीं कर सकते हैं। यह बस समझ में नहीं आता है। एक वस्तु बिल्कुल एक ठोस प्रकार का है, और जब वस्तु ऑब्जेक्ट नष्ट हो जाती है तब तक ऑब्जेक्ट बनने के समय से इसका ठोस प्रकार बदला नहीं जा सकता है (काला जादू के बावजूद)। आप जो करने की कोशिश कर रहे हैं उसे पूरा करने के लिए, लेकिन आपके द्वारा निर्धारित कक्षा पदानुक्रम के साथ, आपको उस ग्राहक ऑब्जेक्ट को नष्ट करना होगा जिसे आप एक स्तरीय ग्राहक ऑब्जेक्ट में बदलना चाहते हैं, एक नया स्तर-एक ग्राहक ऑब्जेक्ट बनाएं, और ग्राहक ऑब्जेक्ट से सभी प्रासंगिक गुणों को प्रति-एक ग्राहक ऑब्जेक्ट पर कॉपी करें। इस तरह आप अपने वर्ग पदानुक्रम के साथ ऑब्जेक्ट उन्मुख भाषाओं में ऑब्जेक्ट्स के साथ ऐसा करते हैं।

जाहिर है, आपके पास कक्षा पदानुक्रम आपके लिए काम नहीं कर रहा है। जब आप एक-एक ग्राहक बन जाते हैं तो आप वास्तविक जीवन में ग्राहकों को नष्ट नहीं करते हैं! तो वस्तुओं के साथ ऐसा मत करो। इसके बजाए, एक श्रेणी पदानुक्रम के साथ आना जो समझ में आता है, परिस्थितियों को लागू करने के लिए आपको आवश्यक है। आपके उपयोग परिदृश्यों में शामिल हैं:

  • एक ग्राहक जो पहले टायर-एक स्थिति नहीं है अब एक-एक स्थिति बन जाता है।

इसका मतलब है कि आपको एक श्रेणी पदानुक्रम की आवश्यकता है जो इस परिदृश्य को सटीक रूप से कैप्चर कर सके। एक संकेत के रूप में, आप विरासत पर संरचना का पक्ष लेना चाहिए। इसका मतलब है, IsTierOne नामक संपत्ति या DiscountStrategy नाम की एक संपत्ति, जो सर्वोत्तम काम करती है, के आधार पर एक बेहतर विचार हो सकता है।

NHibernate (और जावा के लिए हाइबरनेट) का पूरा उद्देश्य डेटाबेस को अदृश्य बनाना है। ऑब्जेक्ट्स को मूल रूप से ऑब्जेक्ट्स के साथ काम करने की अनुमति देने के लिए, अपने ऑब्जेक्ट्स को लगातार बनाने के लिए दृश्यों के पीछे डेटाबेस के साथ जादुई रूप से डेटाबेस के साथ। NHibernate आपको डेटाबेस के साथ मूल रूप से काम करने देगा, लेकिन यह उस परिदृश्य का प्रकार नहीं है जिसके लिए NHibernate बनाया गया है।

+0

मुझे यह जवाब पसंद आया, लेकिन महसूस किया कि डेविड का थोड़ा बेहतर शब्द था इसलिए मैंने उसे स्वीकार कर लिया। फिर भी, अच्छे उत्तर के लिए बहुत धन्यवाद - जिसे मैंने अप-वोट दिया है। –

2

यह देर से वास्तव में है, लेकिन अगले व्यक्ति कुछ इसी तरह काम करना चाहते करने के लिए काम का हो सकता है:

जबकि अन्य उत्तर सही हैं कि आप चाहिए परिवर्तन ज्यादातर मामलों में discriminator नहीं, तो आप मैप किए गए गुणों के कुछ चालाक उपयोग के साथ, एनएच (कोई देशी एसक्यूएल) के दायरे में पूरी तरह से कर सकते हैं। यहाँ यह का सार FluentNH का उपयोग कर रहा है:

public enum CustomerType //not sure it's needed 
{ 
    Customer, 
    TierOneCustomer 
} 

public class Customer 
{ 
    //You should be able to use the Type name instead, 
    //but I know this enum-based approach works 
    public virtual CustomerType Type 
    { 
     get {return CustomerType.Customer;} 
     set {} //small code smell; setter exists, no error, but it doesn't do anything. 
    } 
    ... 
} 

public class TierOneCustomer:Customer 
{ 
    public override CustomerType Type {get {return CustomerType.TierOneCustomer;} set{}} 
    ... 
} 

public class CustomerMap:ClassMap<Customer> 
{ 
    public CustomerMap() 
    { 
     ... 
     DiscriminateSubClassesOnColumn<string>("CustomerType"); 
     DiscriminatorValue(CustomerType.Customer.ToString()); 
     //here's the magic; make the discriminator updatable 
     //"Not.Insert()" is required to prevent the discriminator column 
     //showing up twice in an insert statement 
     Map(x => x.Type).Column("CustomerType").Update().Not.Insert(); 
    } 
} 

public class TierOneCustomerMap:SubclassMap<TierOneCustomer> 
{ 
    public CustomerMap() 
    { 
     //same idea, different discriminator value 
     ... 
     DiscriminatorValue(CustomerType.TierOneCustomer.ToString()); 
     ... 
    } 
} 

अंतिम परिणाम है कि discriminator मूल्य आवेषण के लिए निर्दिष्ट किया जाता है, और पुनः प्राप्ति पर instantiated प्रकार निर्धारित करने के लिए प्रयोग किया जाता है, लेकिन है तो अगर एक ही साथ एक अलग उप-प्रकार का एक रिकॉर्ड आईडी सहेजा गया है (जैसे कि रिकॉर्ड को यूआई से नए प्रकार तक क्लोन या अन-बाध्य किया गया था), भेदभावकर्ता मूल्य उस आईडी के साथ मौजूदा रिकॉर्ड पर ऑब्जेक्ट प्रॉपर्टी के रूप में अपडेट किया जाता है, ताकि उस प्रकार के भविष्य के पुनर्प्राप्तियां नई वस्तु गुणकों पर सेटर की आवश्यकता होती है क्योंकि AFAIK NHibernate को यह नहीं बताया जा सकता है कि एक संपत्ति केवल पढ़ने के लिए है (और इस प्रकार डीबी को "केवल लिखना"); एनएचबेर्नेट की दुनिया में, यदि आप डीबी को कुछ लिखते हैं, तो आप इसे वापस क्यों नहीं चाहेंगे?

मैंने हाल ही में इस पैटर्न का उपयोग उपयोगकर्ताओं को "टूर" के मूल प्रकार को बदलने की अनुमति देने के लिए किया है, जो वास्तव में वास्तविक "टूर" (एक डिजिटल "विज़िट" के शेड्यूलिंग को नियंत्रित करने वाले नियमों का एक सेट है। यह सुनिश्चित करने के लिए साइट पर सभी उपकरण ठीक से काम करते हैं)। हालांकि वे सभी "टूर शेड्यूल" हैं और सूचियों/कतारों आदि में एकत्रित होने की आवश्यकता है, इसलिए विभिन्न प्रकार के कार्यक्रमों के लिए ओपी के समान डेटा संरचना के लिए कॉल करने के लिए बहुत अलग डेटा और बहुत अलग प्रसंस्करण की आवश्यकता होती है। इसलिए मैं डेटा लेयर पर प्रभाव को कम करने के दौरान एक अलग तरीके से एक TierOneCustomer का इलाज करने की ओपी की इच्छा को पूरी तरह से समझता हूं, इसलिए, यहां जाएं।