2009-03-14 13 views
10

डोमेन मॉडल में केवल पढ़ने वाली सूचियों के लिए सबसे अच्छा अभ्यास क्या है, जिस पर मैं काम कर रहा हूं, मूल और बाल संस्थाएं हैं। कुछ निम्न कोड की तरह:NHibernate

class Order 
{ 
    IList<OrderLine> Lines {get;set;} 
} 

class OrderLine 
{ 
} 

अब मैं चाहता हूँ लाइनों को नियंत्रित करने के लिए अपने आदेश। ऐसा ही कुछ:

class Order 
{ 
    private IList<OrderLine> lines = new List<OrderLine>(); 
    OrderLine[] Lines {get {return this.lines;}} 

    void AddLine(OrderLine line) 
    { 
     this.orders.Add(line); 
    { 
} 

NHibernate लाइनों क्षेत्र के लिए सीधे मैप किया गया है:

class Order 
{ 
    OrderLine[] Lines {get;} 

    void AddLine(OrderLine line); 
} 

इस समय हम निम्नलिखित पद्धति का उपयोग कर रहे हैं।

अब सवाल ...

  • आप ऐसी स्थितियों में क्या अभ्यास करते हैं?
  • करता है किसी को भी उपयोग विधि: सार्वजनिक IEnumerable GetLines()
  • आप संपत्ति के बदले प्रकार के रूप में प्रयोग कर रहे हैं क्या? पढ़ा जा सकता है केवल चयन या IENumerable;
  • क्या यह पूछने का सबसे अच्छा स्थान नहीं है? कृपया सुझाव दें।

अद्यतन: IEnumerable जीत लगता है, फिर भी समाधान अभी भी सही नहीं है ...

उत्तर

9

पैटर्न मैं का उपयोग करें:

class Order 
{ 
    private List<OrderLine> lines = new List<OrderLine>(); 

    IEnumerable<OrderLine> Lines { get { return this.lines; } } 

    void AddLine(OrderLine line) 
    { 
     this.orders.Add(line); 
    } 
} 

आप नेट 3.5 उपयोग कर रहे हैं आप सभी खोज मिल कार्यक्षमता जिसे आप LINQ का उपयोग करके IENumerable के लिए चाहते हैं, और आप अपने संग्रह कार्यान्वयन को छुपाते हैं।

लौटने ऑर्डर लाइन [] के साथ समस्या यह है कि अपने संग्रह बाह्य जैसे संशोधित किया जा सकता है:

Order.Lines[0] = new OrderLine(). 
+0

के बारे में "Order.Lines [0] नई ऑर्डर लाइन() =," यह नहीं कर सकते। प्रत्येक बार जब आप लाइनों तक पहुंचते हैं तो सरणी की नई प्रति जारी की जाती है (मुझे यह पसंद नहीं है ...)। आईनेमेरेबल में सूची कार्यक्षमता की कमी है, मेरा मतलब है गणना, सूचकांक द्वारा उपयोग। बेशक, LINQ इसे शामिल करता है। धन्यवाद! –

+0

यहां, आप अभी भी लाइन्स प्रॉपर्टी को सूची पर डाल सकते हैं और इस तरह से संग्रह को संशोधित कर सकते हैं ... –

+2

हां, लेकिन आपको कास्टिंग करना है। यह सुरक्षा के बारे में इतना नहीं है लेकिन यह दिखाने के बारे में कि आपको संग्रह में क्या करने की अनुमति है। आप इसे वापस कर सकते हैं। लाइनें। जैसा कि आप अतिरिक्त सुरक्षा चाहते हैं। – gcores

3

मैं ReadOnlyCollection के रूप में संग्रह का पर्दाफाश और संग्रह बनाए रखने के लिए AddX और RemoveX तरीकों का उपयोग। हमने अभी 3.5 तक स्विच किया है और मैं इसके बजाय आईनेमरेबल को उजागर करने के बारे में सोच रहा हूं। ,

public void AddPlayer(Player player) 
    { 
     player.Company = this; 
     this._Players.Add(player); 
    } 

    public void RemovePlayer(Player player) 
    { 
     player.Company = null; 
     this._Players.Remove(player); 
    } 
+0

ये, लगता है कि आईन्यूमेरेबल धड़कता है केवल पढ़ने के लिए ... ReadOnlyCollection API को भ्रमित कर देता है। इसमें अभी भी विधि है जो रनटाइम में अपवाद फेंक देगा ... –

+1

माइक - मुझे लगता है कि आप इस पर गलत हैं। एक सूची लौटा रहा है .अनरेडऑनली() एक ऐड विधि का पर्दाफाश करता है लेकिन ReadOnlyCollection नहीं करता है। ReadOnlyCollection System.Collections.ObjectModel में है इसलिए इसे अक्सर अनदेखा किया जाता है। –

+0

मजेदार, हाँ यह सच है ..मैंने इसे अनदेखा किया। आपका बहुत बहुत धन्यवाद। –

1

मैं एक सूची है जो संशोधित नहीं किया जाना चाहिए उजागर कर रहा हूँ तो मैं का उपयोग करें: NHibernate के साथ ज्यादातर मामलों में बच्चे को तो उजागर जोड़े और तरीकों निकालें माता-पिता के लिए एक संदर्भ आप उस रिश्ते को बनाए रखने के लिए अनुमति देता है IENumerable और उपज। मुझे यह पता चलता है कि एनएचबेरांटे के साथ संयोजन में ReadOnlyCollections का उपयोग करने की कोशिश कर रहा है।

इस दृष्टिकोण के साथ, आपके पास अभी भी निजी लाइन फ़ील्ड है जो मैप किए गए और एनएचबेर्नेट के माध्यम से पॉप्युलेट हो जाती है; हालांकि, संग्रह के लिए सार्वजनिक पहुंच iterators के माध्यम से किया जाता है। आप इस लाइन्स प्रॉपर्टी के साथ अंतर्निहित सूची में जोड़ या हटा नहीं सकते हैं।

उदाहरण के लिए:

public IEnumerable<OrderLine> Lines { 
    get { 
     foreach (OrderLine aline in lines) { 
      yield return aline; 
     } 
    } 
} 
+0

क्यों न केवल "वापसी लाइनें"? आप कास्टिंग से रक्षा कर रहे हैं? उपज के साथ समाधान का मतलब है कि गणना() को foreach की आवश्यकता होगी और सभी समर्थित आईट्स (आलसी भार के मामले में) लोड होगा। –

+0

उपज के साथ संयुक्त आईनेमेरेबल आपको वस्तुओं को जोड़ने/हटाने में सक्षम होने के बिना संग्रह को चलाने की अनुमति देता है। –

+0

खैर, आईनेमेरेबल सभी अपने आप को आइटम जोड़ने/हटाने से रोक देगा - इसलिए 'सार्वजनिक आईनेमरेबल लाइन्स {वापसी {वापसी लाइनें; }} 'पर्याप्त होना चाहिए। – Dav

14

मैं इसे इस तरह कार्य करें:

public class Order 
{ 
     private ISet<OrderLine> _orderLines = new HashedSet<OrderLine>(); 

     public ReadOnlyCollection<OrderLine> OrderLines 
     { 
      get { return new List<OrderLine>(_orderLines).AsReadOnly(); } 
     } 

     public void AddOrderLine(OrderLine ol) 
     { 
      ... 
     } 
} 

फिर, offcourse, मानचित्रण में, NHibernate _orderLines क्षेत्र का उपयोग करने के लिए कहा जाता है:

<set name="OrderLine" access="field.camelcase-underscore" ... > 
... 
</set> 
+0

कोड के बाद आपके कोड के साथ असफल हो जाएगा: ऑर्डर। ऑर्डरलाइन! = ऑर्डर। ऑर्डरलाइन; मुझे यकीन नहीं है कि यह बुरा है या नहीं ... वैसे भी धन्यवाद। –

+0

इससे कोई फर्क नहीं पड़ता, क्योंकि आपको इसकी तुलना नहीं करना चाहिए :) –

+0

अच्छा समाधान। इससे मुझे बहुत मदद मिली। धन्यवाद! – CalebHC

0

मैंने एनएचबर्ननेट में केवल पढ़ने योग्य सूचियों के लिए सर्वोत्तम दृष्टिकोण की तलाश में कई दिन बिताए हैं। इस चर्चा ने मुझे हमारी परियोजना के अनुकूल होने के लिए बहुत मदद की।

  1. बैकअप क्षेत्रों दुकान संग्रह
  2. IEnumerable < टी> प्रयोग किया जाता है करने के लिए उपयोग किया जाता है ग्राहकों के लिए मजबूर करने संग्रह AddLine() और RemoveLine का उपयोग() पद्धतियों का पर्दाफाश करने के:

    वहाँ एक दृष्टिकोण मैं उपयोग करने के लिए शुरू कर दिया है ।

  3. ReadOnlyCollection प्रकार IENumerable के अलावा उपयोग किया जाता है।

कोड:

public class Order 
{ 
    private readonly IList<OrderLine> lines = new List<OrderLine>(); 

    public virtual IEnumerable<OrderLine> Lines 
    { 
     get 
     { 
      return new ReadOnlyCollection<OrderLine>(lines); 
     } 
    } 

    public void AddLine(OrderLine line) 
    { 
     if (!lines.Contains(line)) 
     { 
      this.lines.Add(line); 
      line.Order = this; 
     } 
    } 

    public void RemoveLine(OrderLine line) 
    { 
     if (lines.Contains(line)) 
     { 
      this.lines.Remove(line); 
      line.Order = null; 
     } 
    } 
} 

public class OrderLine 
{ 
    public Order Order { get; set; } 
}