2013-02-21 23 views
13

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

ऐसा लगता है कि मुझे ग्राहकों की सूची प्राप्त करने के लिए संदर्भ का उपयोग करना चाहिए (पीओसीओ या CustomerViewModels पर मैप किया गया) और फिर संदर्भ को तुरंत बंद करें। फिर, जब उपयोगकर्ता सूची में CustomerViewModels में से एक का चयन करता है तो यूआई के ग्राहक गुण अनुभाग पॉप्युलेट हो जाते हैं।

अगला वे एक बटन को बचाने मार करने पर नाम, प्रकार, वेबसाइट के पते, कंपनी के आकार, आदि को बदल सकते हैं, मैं तो एक नया संदर्भ खोलते हैं, तो CustomerViewModel से आईडी का उपयोग है कि ग्राहक रिकॉर्ड को पुनः प्राप्त करने, और से प्रत्येक को अद्यतन इसकी गुण अंत में, मैं SaveChanges() पर कॉल करता हूं और संदर्भ बंद करता हूं। यह काम का एक बहुत है।

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

कोई सुझाव? धन्यवाद।


@PGallagher - पूरी तरह से उत्तर के लिए धन्यवाद।
@ ब्रिस - आपका इनपुट उपयोगी है

हालांकि, @Manos डी 'अनावश्यक कोड' का प्रतीक मुझे टिप्पणी करता है। मुझे एक उदाहरण के माध्यम से जाने दो। आइए कहें कि मैं डेटाबेस में ग्राहकों को संग्रहीत कर रहा हूं और मेरे ग्राहक गुणों में से एक CommunicationMethod है।

[Flags] 
public enum CommunicationMethod 
{ 
    None = 0, 
    Print = 1, 
    Email = 2, 
    Fax = 4 
} 

यूआई WPF में मेरे प्रबंधन ग्राहकों पेज के लिए ग्राहक संचार पद्धति (प्रिंट, ईमेल, फैक्स) के तहत तीन चेक बॉक्स शामिल होंगे। मैं उस एनम पर प्रत्येक चेकबॉक्स को बाध्य नहीं कर सकता, यह समझ में नहीं आता है। इसके अलावा, यदि उपयोगकर्ता उस ग्राहक पर क्लिक करता है, तो उठता है और दोपहर के भोजन के लिए जाता है ... संदर्भ घंटों के लिए वहां बैठता है जो खराब है। इसके बजाय, यह मेरी विचार प्रक्रिया है।

अंतिम उपयोगकर्ता सूची से ग्राहक को चुनता है। मैं एक संदर्भ को नया करता हूं, उस ग्राहक को ढूंढता हूं और एक ग्राहक व्यू मॉडेल लौटाता हूं, फिर संदर्भ बंद हो जाता है (मैंने यहां सादगी के लिए भंडार छोड़ दिया है)।

using(MyContext ctx = new MyContext()) 
{ 
    CurrentCustomerVM = new CustomerViewModel(ctx.Customers.Find(customerId)); 
} 

अब उपयोगकर्ता जाँच/प्रिंट, ईमेल, फैक्स बटन सही का निशान के रूप में वे CustomerViewModel है, जो भी एक सहेजें() विधि है में तीन bool गुण के लिए बाध्य कर रहे हैं कर सकते हैं। यहाँ जाता हैं।

public class CustomerViewModel : ViewModelBase 
{ 
    Customer _customer; 

    public CustomerViewModel(Customer customer) 
    { 
     _customer = customer; 
    } 


    public bool CommunicateViaEmail 
    { 
     get { return _customer.CommunicationMethod.HasFlag(CommunicationMethod.Email); } 
     set 
     { 
      if (value == _customer.CommunicationMethod.HasFlag(CommunicationMethod.Email)) return; 

      if (value) 
       _customer.CommunicationMethod |= CommunicationMethod.Email; 
      else 
       _customer.CommunicationMethod &= ~CommunicationMethod.Email; 
     } 
    } 
    public bool CommunicateViaFax 
    { 
     get { return _customer.CommunicationMethod.HasFlag(CommunicationMethod.Fax); } 
     set 
     { 
      if (value == _customer.CommunicationMethod.HasFlag(CommunicationMethod.Fax)) return; 

      if (value) 
       _customer.CommunicationMethod |= CommunicationMethod.Fax; 
      else 
       _customer.CommunicationMethod &= ~CommunicationMethod.Fax; 
     } 
    } 
    public bool CommunicateViaPrint 
    { 
     get { return _customer.CommunicateViaPrint.HasFlag(CommunicationMethod.Print); } 
     set 
     { 
      if (value == _customer.CommunicateViaPrint.HasFlag(CommunicationMethod.Print)) return; 

      if (value) 
       _customer.CommunicateViaPrint |= CommunicationMethod.Print; 
      else 
       _customer.CommunicateViaPrint &= ~CommunicationMethod.Print; 
     } 
    } 

    public void Save() 
    { 
     using (MyContext ctx = new MyContext()) 
     { 
      var toUpdate = ctx.Customers.Find(_customer.Id); 
      toUpdate.CommunicateViaEmail = _customer.CommunicateViaEmail; 
      toUpdate.CommunicateViaFax = _customer.CommunicateViaFax; 
      toUpdate.CommunicateViaPrint = _customer.CommunicateViaPrint; 

      ctx.SaveChanges(); 
     } 
    } 
} 

क्या आप इसके साथ कुछ गलत देखते हैं?

उत्तर

17

लंबे समय से चलने वाले संदर्भ का उपयोग करना ठीक है; आपको केवल प्रभावों से अवगत होना चाहिए।

एक संदर्भ काम की एक इकाई का प्रतिनिधित्व करता है। जब भी आप SaveChanges को कॉल करते हैं, ट्रैक किए जा रहे इकाइयों में सभी लंबित परिवर्तन डेटाबेस में सहेजे जाएंगे। इस वजह से, आपको प्रत्येक संदर्भ को समझने की आवश्यकता होगी। उदाहरण के लिए, यदि आपके पास उत्पादों का प्रबंधन करने के लिए ग्राहकों और दूसरे को प्रबंधित करने के लिए एक टैब है, तो आप प्रत्येक के लिए एक संदर्भ का उपयोग कर सकते हैं ताकि जब उपयोगकर्ता ग्राहक टैब पर सहेजते हैं, तो उत्पादों में किए गए सभी परिवर्तन भी सहेजे नहीं जाते हैं।

एक संदर्भ भी DetectChanges को धीमा कर सकता है के द्वारा पता लगाया संस्थाओं का एक बहुत हो रही है। इसे कम करने का एक तरीका परिवर्तन ट्रैकिंग प्रॉक्सी का उपयोग कर है।

एक इकाई लोड हो रहा है और बचत कि इकाई काफी लंबा हो सकता है के बीच के समय के बाद से, एक आशावादी संगामिति अपवाद मारने की मौका अल्पकालिक संदर्भों के साथ से अधिक है। ये अपवाद तब होते हैं जब एक इकाई को लोड करने और सहेजने के बीच बाहरी रूप से बदल दिया जाता है। Handling these exceptions बहुत सरल है, लेकिन यह अभी भी कुछ पता होना चाहिए।

WPF में लंबे समय तक रहने वाले संदर्भों के साथ आप एक अच्छी चीज कर सकते हैं DbSet.Local संपत्ति (उदा। संदर्भ। ग्राहक। लोकल) से बंधे हैं। यह एक अवलोकन करने योग्य चयन है जिसमें सभी ट्रैक की गई इकाइयां शामिल हैं जिन्हें हटाने के लिए चिह्नित नहीं किया गया है।

उम्मीद है कि यह आप आप जो दृष्टिकोण में मदद करने के निर्णय लेने में सहायता करने के लिए थोड़ा और जानकारी देता है।

+0

ग्रेट उत्तर। आपके उत्तर के लिए धन्यवाद: ईएफ टीम के सदस्य का जवाब हमेशा मूल्यवान है। – JYL

0

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

एक संदर्भ खुलने, एक रिकॉर्ड हथियाने, संदर्भ को बंद करने और फिर एक नया संदर्भ से एक वस्तु के लिए संशोधित गुण को कॉपी अनावश्यक कोड की epitomy है। तुम अकेले मूल संदर्भ छोड़ने के लिए और का उपयोग करें कि SaveChanges करने के लिए करने वाले हैं()।

आप संगामिति मुद्दों से निपटने के लिए आप इकाई की रूपरेखा के अपने संस्करण के लिए "संगामिति से निपटने" के बारे में एक Google खोज करना चाहिए देख रहे हैं।

एक उदाहरण के रूप मैं this मिल गया है। टिप्पणी करने के लिए

जवाब में

संपादित करें:

तो क्या मैं समझता हूँ कि आप एक रिकार्ड के स्तंभों में से एक सबसेट की जरूरत है नए मूल्यों के साथ अधिरोहित जा करने के लिए, जबकि बाकी अप्रभावित है से? यदि हां, तो, आपको इन नए कॉलम को "नई" ऑब्जेक्ट पर मैन्युअल रूप से अपडेट करने की आवश्यकता होगी।

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

+0

मेरे पोस्ट अपडेट को समझाते हुए बताते हुए कि मैं कस्टमर व्यू मॉडेल का उपयोग क्यों कर रहा हूं और संदर्भ – BBauer42

3

माइक्रोसॉफ्ट संदर्भ:

http://msdn.microsoft.com/en-gb/library/cc853327.aspx

वे कहते हैं;

सीमा ObjectContext

के दायरे ज्यादातर मामलों में, आप एक का उपयोग कर बयान के भीतर एक ObjectContext उदाहरण बनाना चाहिए (का उपयोग करते हुए ... अंत विजुअल बेसिक में उपयोग करते हुए)।

यह सुनिश्चित करके प्रदर्शन बढ़ा सकता है कि ऑब्जेक्ट संदर्भ से जुड़े संसाधनों को स्वचालित रूप से का निपटारा किया जाता है जब कोड कथन ब्लॉक से बाहर निकलता है।

हालांकि, जब नियंत्रण वस्तु संदर्भ द्वारा प्रबंधित वस्तुओं के लिए बाध्य कर रहे हैं, ObjectContext उदाहरण जब तक बंधन की जरूरत है और मैन्युअल रूप से निपटाया है बनाए रखा जाना चाहिए।

अधिक जानकारी के लिए, ऑब्जेक्ट सर्विसेज (एंटिटी फ्रेमवर्क) में प्रबंधन संसाधन देखें। http://msdn.microsoft.com/en-gb/library/bb896325.aspx

जो कहता है;

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


StackOverflow संदर्भ:

यह StackOverflow सवाल भी कुछ उपयोगी जवाब है ...

Entity Framework Best Practices In Business Logic?

कहाँ कुछ सुझाव दिया है कि आप एक के लिए अपने संदर्भ को बढ़ावा देने के उच्च स्तर और यहां से संदर्भित करें, इस प्रकार केवल एक एकल संदर्भ रखें।


मेरे दस लायक पेंस:

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

स्पष्ट रूप से सरल ऐप्स में, यह एक समस्या नहीं है, हालांकि, यदि आपके पास एकाधिक स्क्रीन हैं, तो सभी डेटा का उपयोग करके, आप परेशानी में समाप्त हो सकते हैं, जब तक कि आप अपने संदर्भ को सही तरीके से निपटाने के लिए निश्चित नहीं हैं।

इसलिए मैंने आपके द्वारा उल्लिखित एक समान विधि को नियोजित किया है, जहां मैंने AddOrUpdate मेरे प्रत्येक रेपॉजिटरीज़ में विधि जोड़ दी है, जहां मैं अपनी नई या संशोधित इकाई में पास करता हूं, और अद्यतन करता हूं या इसके आधार पर इसे जोड़ता हूं वह मौजूद है।


अपडेट कर रहा है इकाई गुण:

तथापि गुण को अद्यतन करने के बारे में, मैं एक साधारण समारोह जो एक इकाई से एक और करने के लिए सभी गुण कॉपी करने के लिए प्रतिबिंब का उपयोग करता है का उपयोग किया है;

Public Shared Function CopyProperties(Of sourceType As {Class, New}, targetType As {Class, New})(ByVal source As sourceType, ByVal target As targetType) As targetType 
    Dim sourceProperties() As PropertyInfo = source.GetType().GetProperties() 
    Dim targetProperties() As PropertyInfo = GetType(targetType).GetProperties() 

    For Each sourceProp As PropertyInfo In sourceProperties 
     For Each targetProp As PropertyInfo In targetProperties 
      If sourceProp.Name <> targetProp.Name Then Continue For 

      ' Only try to set property when able to read the source and write the target 
      ' 
      ' *** Note: We are checking for Entity Types by Checking for the PropertyType to Start with either a Collection or a Member of the Context Namespace! 
      ' 
      If sourceProp.CanRead And _ 
        targetProp.CanWrite Then 
       ' We want to leave System types alone 
       If sourceProp.PropertyType.FullName.StartsWith("System.Collections") Or (sourceProp.PropertyType.IsClass And _ 
         sourceProp.PropertyType.FullName.StartsWith("System.Collections")) Or sourceProp.PropertyType.FullName.StartsWith("MyContextNameSpace.") Then 
        ' 
        ' Do Not Store 
        ' 
       Else 

        Try 

         targetProp.SetValue(target, sourceProp.GetValue(source, Nothing), Nothing) 

        Catch ex As Exception 

        End Try 

       End If 
      End If 

      Exit For 
     Next 
    Next 

    Return target 
End Function 

जहां मैं कुछ ऐसा करता हूं;

dbColour = Classes.clsHelpers.CopyProperties(Of Colour, Colour)(RecordToSave, dbColour) 

इस कोड की राशि मैं निश्चित रूप से प्रत्येक भंडार के लिए लिखने के लिए कम हो जाती है!

+0

पूरी तरह से टिप्पणियों के लिए धन्यवाद। क्या आप क्षैतिज नियम के तहत किए गए ओपी के अपडेट के साथ कुछ भी गलत देखते हैं? एक बार फिर धन्यवाद। – BBauer42