2009-10-26 15 views
15

में भेदित संघों को मैं सोच रहा हूं कि एफ # के भेदभाव वाले संघ का समर्थन करने के लिए एनएचबेर्नेट को बढ़ाने का कोई अपेक्षाकृत आसान तरीका है या नहीं। न केवल एक IUserType या ICompositeUserType, लेकिन कुछ सामान्य है कि मैं डीयू की वास्तविक सामग्री के बावजूद फिर से उपयोग कर सकता हूं।NHibernate

type RequestInfo = 
    | Id of int 
    | Name of string 

यह संकलित एक सार RequestInfo वर्ग में, ठोस उपवर्गों आईडी और नाम के साथ:

उदाहरण के लिए, मैं एक संपत्ति RequestInfo कहा जाता है, जो एक संघ के रूप में परिभाषित है लगता है। मैं एफ # प्रतिबिंब के साथ यह सारी जानकारी ठीक से प्राप्त कर सकता हूं। इस मामले में, मैं इसे "RequestInfo_Tag", "RequestInfo_Id", "RequestInfo_Name" के साथ डेटाबेस में संग्रहीत कर सकता हूं।

जैसा कि मैं एनएचबीर्नेट नौसिखिया हूं, इस दृष्टिकोण का पालन करने की कोशिश में मैं किस तरह की समस्याएं चलाने जा रहा हूं? क्या अधिक जटिल मामले निपटने के लिए असंभव होने जा रहे हैं? उदाहरण के लिए, नेस्टेड भेदभाव वाले संघों के बारे में क्या? क्या कोई तरीका है कि मैं बाकी यूनियन के पढ़ने को "आईसीओमोपसाइट यूज़र टाइप" के पढ़ने के लिए "बंद कर सकता हूं"?

अधिक महत्वपूर्ण बात यह मेरी क्वेरीिंग क्षमताओं को गड़बड़ कर देगी? मतलब, क्या मुझे डीबी में वास्तविक कॉलम नामों को जानना होगा; मैं मानदंड नहीं कर पाऊंगा। ईक (कुछ डिस्प्लेनियन) और क्या यह सब हल हो गया है?

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

धन्यवाद!

पीएस अशिष्ट नहीं होना चाहिए, लेकिन यदि आपके उत्तर में "सी # का उपयोग" होता है, तो यह बहुत उपयोगी नहीं है।

+1

बहुत ही रोचक सवाल। मैं एनएचबर्ननेट और एफ # दोनों में काफी धाराप्रवाह हूं, मुझे कुछ समय मिल जाएगा जब मुझे कुछ समय मिल जाएगा –

+0

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

+0

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

उत्तर

7

मैं एफ # के प्रकार प्रणाली के साथ एनएचबर्ननेट का उपयोग करने के लिए पर्याप्त बहादुर नहीं रहा हूं, लेकिन यह वास्तव में एफ # कंपाइलर द्वारा उत्पन्न किए गए चीज़ों के परिप्रेक्ष्य से देखने में मदद कर सकता है।

यदि आप परावर्तक में अपने विकृत संघ को देखते हैं, तो वास्तव में तीन वर्ग उत्पन्न होते हैं (और यदि आप निजी डीबग प्रॉक्सी को गिनते हैं तो अधिक)।

public abstract class RequestInfo : IStructuralEquatable, IComparable, IStructuralComparable 

प्रथम श्रेणी, RequestInfo, सार है, और वास्तव में संघ में अन्य प्रकारों द्वारा लागू किया जाता है।

// Nested Types 
    [Serializable, DebuggerTypeProxy(typeof([email protected])), DebuggerDisplay("{__DebugDisplay()}")] 
    public class _Id : Program.RequestInfo 
    { 
     // Fields 
     [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode] 
     public readonly int id1; 

     // Methods 
     [CompilerGenerated, DebuggerNonUserCode] 
     public _Id(int id1); 
    } 
    [Serializable, DebuggerTypeProxy(typeof([email protected])), DebuggerDisplay("{__DebugDisplay()}")] 
    public class _Name : Program.RequestInfo 
    { 
     // Fields 
     [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode] 
     public readonly string name1; 

     // Methods 
     [CompilerGenerated, DebuggerNonUserCode] 
     public _Name(string name1); 
    } 

इसलिए जब आप कार्य करें:

let r=Id(5) 
let s=Name("bob") 

आर और एस _ id और नाम_ के उदाहरण क्रमश: कर रहे हैं।

तो आपके सवाल का जवाब की संभावना निम्नलिखित प्रश्नों में से एक के लिए जवाब है:

  • मैं कैसे nhibernate में एक अमूर्त वर्ग के लिए मैप करते हैं?
  • मैं एनएचबेर्नेट को फैक्ट्री विधि का उपयोग कैसे कर सकता हूं?
  • मैं अपरिवर्तनीय वस्तुओं के लिए नक्शा निबर्ननेट कैसे बना सकता हूं?
  • मैं NHibernate (संभवतः IUserType के साथ) में एक कस्टम प्रकार को कैसे कार्यान्वित कर सकता हूं।

दुर्भाग्य से, मैं आपको इनमें से किसी के लिए एक सुसंगत उत्तर देने के लिए पर्याप्त समझदार नहीं हूं, लेकिन मुझे यकीन है कि यहां किसी और ने इन तीन समाधानों में से कम से कम एक किया है।

मुझे लगता है कि आप विरासत रणनीतियों के लिए उपयोग की जाने वाली विधियों का उपयोग कर सकते हैं, उदाहरण के लिए, एक भेदभावकर्ता कॉलम, लेकिन मुझे डर है कि एक डिफ़ॉल्ट कन्स्ट्रक्टर की कमी इस समस्याग्रस्त हो जाती है। तो मुझे लगता है कि एक कस्टम प्रकार का उपयोग समाधान है।

कुछ नगण्य के बाद, यहाँ (संभवत: गाड़ी और या टूट) कस्टम उपयोगकर्ता प्रकार है:

type RequestInfo = 
    | Id of int 
    | Name of string 

type RequestInfoUserType() as self = 
    interface IUserType with 
     member x.IsMutable = false 
     member x.ReturnedType = typeof<RequestInfo> 
     member x.SqlTypes = [| NHibernate.SqlTypes.SqlType(Data.DbType.String); NHibernate.SqlTypes.SqlType(Data.DbType.Int32); NHibernate.SqlTypes.SqlType(Data.DbType.String) |] 
     member x.DeepCopy(obj) = obj //Immutable objects shouldn't need a deep copy 
     member x.Replace(original,target,owner) = target // this might be ok 
     member x.Assemble(cached, owner) = (x :> IUserType).DeepCopy(cached) 
     member x.Disassemble(value) = (x :> IUserType).DeepCopy(value) 

     member x.NullSafeGet(rs, names, owner)= 
      // we'll use a column as a type discriminator, and assume the first mapped column is an int, and the second is a string. 
      let t,id,name = rs.GetString(0),rs.GetInt32(1),rs.GetString(2) 
      match t with 
       | "I" -> Id(id) :> System.Object 
       | "N" -> Name(name) :> System.Object 
       | _ -> null 
     member x.NullSafeSet(cmd, value, index)= 
      match value with 
       | :? RequestInfo -> 
        let record = value :?> RequestInfo 
        match record with 
         | Id(i) -> 
          cmd.Parameters.Item(0) <- "I" 
          cmd.Parameters.Item(1) <- i 
         | Name(n) -> 
          cmd.Parameters.Item(0) <- "N" 
          cmd.Parameters.Item(2) <- n 
       | _ -> raise (new ArgumentException("Unexpected type")) 

     member x.GetHashCode(obj) = obj.GetHashCode() 
     member x.Equals(a,b) = 
      if (Object.ReferenceEquals(a,b)) then 
       true 
      else 
       if (a=null && b=null) then 
        false 
       else 
        a.Equals(b) 
    end 

इस कोड को निश्चित रूप से अधिक सामान्य बनाया जा सकता है, और शायद अपने वास्तविक डोमेन परत में नहीं होना चाहिए, लेकिन मैं सोचा कि IUserType के एफ # कार्यान्वयन पर एक स्टैब लेने के लिए उपयोगी होगा।

आपका मैपिंग फ़ाइल तब की तरह कुछ करना होगा:

<property name="IdOrName" type="MyNamespace.RequestInfoUserType, MyAssembly" > 
    <column name="Type"/> 
    <column name="Id"/> 
    <column name="Name"/> 
</property> 

आप शायद कस्टम प्रयोक्ता प्रकार कोड के लिए एक मामूली ट्वीक साथ "प्रकार" के लिए एक कॉलम के बिना प्राप्त कर सकते हैं।

मुझे नहीं पता कि ये कस्टम उपयोगकर्ता प्रकार क्वेरी/आईसीआरटीरिया के साथ कैसे काम करते हैं, क्योंकि मैंने वास्तव में कस्टम उपयोगकर्ता प्रकारों के साथ वास्तव में काम नहीं किया है।

+0

हाँ, एक उदाहरण को मैप करना अपेक्षाकृत आसान होना चाहिए। लेकिन जब एक डीयू में एक और डीयू या कुछ होता है तो क्या होगा? मुझे लगता है कि मुझे कुछ उन्नत समग्र उपयोगकर्ता प्रकार की आवश्यकता है जो इस तरह की चीज के लिए सभी मामलों में पूरी तरह से मानचित्रण करने के लिए रिकर्सिव है। मैं इस बात से भी चिंतित हूं कि यह मानदंड करने के लिए कैसे दिखाता है। – MichaelGG

+0

यह सुनिश्चित नहीं है कि मैं इसे कैसे संभालूं, लेकिन मुझे संदेह है कि आप उपरोक्त मेरे उदाहरण के समान गहरे पैटर्न मिलान निर्माण का उपयोग कर सकते हैं। – JasonTrue