WCF RIA सेवाएँ। प्रारंभ। भाग 1WCF RIA सेवाएँ। डेटा प्राप्त करें। भाग २WCF RIA सेवाएँ। डेटा अपडेट। भाग ३WCF RIA सेवाएँ। पेश है मॉडल-व्यू-व्यूमॉडल (एमवीवीएम) पैटर्न। भाग ४पिछले पाठ में, हमने WCF RIA सेवाओं की डेटा अधिग्रहण क्षमताओं पर करीब से नज़र डाली। आज हम डेटा को अपडेट करने की प्रक्रिया के बारे में बात करेंगे, जो अधिक जटिल है।
परिचयात्मक भाग दूसरे पाठ में बनाई गई परियोजना है।
IQueryable <T> और अभिव्यक्ति ट्री मैजिक
पहले पाठ में, हमने एक डोमेन सेवा बनाई जो कुछ इस तरह दिखाई देती है:
public IQueryable<Task> GetTasks() { return this.ObjectContext.Tasks; }
यदि आप थोड़ा सोचते हैं कि यह कैसे काम करता है, तो यह स्पष्ट हो जाएगा कि पूरी तालिका प्रत्येक विधि कॉल के साथ डेटाबेस से निकाली गई है।
हालाँकि, यह केवल पहली नज़र में है। आइए देखें कि अभिव्यक्ति के पेड़ और आस्थगित निष्पादन क्या हैं।
So. जब "गेटकट्स" विधि कहा जाता है, इसका मतलब यह नहीं है कि डेटाबेस का अनुरोध किया जा रहा है और डेटा पुनर्प्राप्त किया जा रहा है। वास्तव में, यह सिर्फ एक्सप्रेशन ट्री बनाता है और इसे IQueryable के रूप में लौटाता है, जो केवल यह बताता है कि इस विधि द्वारा क्या वापस किया जा सकता है। इस मामले में, सैद्धांतिक रूप से संपूर्ण कार्य तालिका प्राप्त करना संभव है। एक्सप्रेशन ट्री में यह भी बताया गया है कि क्लाइंट साइड में क्या लौटाया जा सकता है। क्वेरी को सीधे निष्पादित किया जाता है और डेटाबेस से डेटा निकालने की प्रक्रिया केवल उस समय होती है जब कोई संग्रह संग्रह को बदलने की कोशिश कर रहा होता है जो अभिव्यक्ति ट्री प्रदान करता है / वर्णन करता है। हालाँकि, अनुरोध भेजे जाने के बाद प्राप्तकर्ता द्वारा अभिव्यक्ति ट्री को बदलना संभव है, और यह बदले में, परिणाम भी बदल सकता है जो अंततः संग्रह को भर देगा।
अभिव्यक्ति के पेड़ को बदलने की क्षमता डेटा निष्कर्षण प्रक्रिया से पहले तुरंत मौजूद है। उदाहरण के लिए:
TasksDomainContext context = new TasksDomainContext(); taskDataGrid.ItemsSource = context.Tasks; EntityQuery<Task> query = context.GetTasksQuery(); LoadOperation<Task> loadOp = context.Load(query.Where(t=>t.TaskId == 1));
दूसरी पंक्ति डोमेन संदर्भ के माध्यम से कार्य संग्रह को बांधती है, जो वास्तव में अभी भी खाली है, क्योंकि डोमेन संदर्भ का गठन होता है। तब EntityQuery संदर्भ से बाहर हो जाता है। डेटाबेस से अभी भी कोई प्रत्यक्ष क्वेरी निष्पादन और डेटा पुनर्प्राप्ति नहीं है। हालाँकि, EntityQuery आपको एक अभिव्यक्ति ट्री बनाने की अनुमति देता है, जिसके आधार पर, सर्वर पर, विधि को कॉल करने के बाद, डेटाबेस के लिए एक क्वेरी उत्पन्न की जाएगी और डेटा निकाला जाएगा। इस मामले में, पूरी तालिका को पुनर्प्राप्त करना संभव है। और केवल जब "लोड" विधि कहा जाता है, तो परिवर्तित अभिव्यक्ति ट्री को स्थानांतरित किया जाता है, जिसमें "कहां" फिल्टर शामिल है, और अनुरोध को संसाधित करने के बाद, केवल एक पंक्ति वापस आ जाएगी, जिसका मान "आईडी" कॉलम में "1" होगा। सर्वर भाग में एक एसिंक्रोनस कॉल होगा, एक अभिव्यक्ति ट्री संचारित होगा और निष्कर्षण होगा। हालांकि, सर्वर साइड पर भी, अनुरोध पहले से ही संशोधित किया जाएगा और केवल एक पंक्ति डेटाबेस से वापस आ जाएगी। जब आप इस पद्धति को कहते हैं, तो आप केवल SQL प्रश्नों को निष्पादित करने के तरीके को देखकर इसे सत्यापित कर सकते हैं। यही है, डेटाबेस से कई पंक्तियों और एक पंक्ति को निकालने के लिए एक अलग विधि के निर्माण की आवश्यकता नहीं है, जो प्रोग्रामर के जीवन को आसान बनाता है।
DomainContext कैशिंग और परिवर्तन ट्रैकिंग
कार्य का तर्क समाप्त कर दिया गया था। लेकिन इससे पहले कि हम कोड पार्सिंग में उतरें, हमें डब्ल्यूसीएफ आरआईए सर्विसेज की कुछ अवधारणाओं के माध्यम से छांटना होगा। उपरोक्त उन सभी चीज़ों से दूर है जो एक डोमेन संदर्भ के पर्दे के पीछे होती हैं। उदाहरण के लिए, एक प्रॉक्सी कॉल हो सकती है। आपके द्वारा प्राप्त की जाने वाली कोई भी संस्था या उनके संग्रह क्लाइंट-साइड डोमेन संदर्भ द्वारा कैश किए जाते हैं। यह इस कारण से है कि यह संभव हो जाता है, जैसा कि ऊपर दिए गए उदाहरण में, सीधे अनुरोध को निष्पादित करने से पहले आइटम संग्रह को कार्य संग्रह में बाँधने के लिए। इस संग्रह को वर्तमान में बदल दिया जाएगा, और यूआई में डेटा उस समय स्वचालित रूप से अपडेट किया जाएगा जब उत्तर सर्वर के लिए एक अतुल्यकालिक कॉल के बाद आएगा। कैशिंग के अलावा, डोमेन संदर्भ कैश्ड निकाय में किसी भी परिवर्तन के बारे में जानकारी संग्रहीत करता है, और इसलिए हमेशा जानता है कि क्या परिवर्तन, विलोपन या इसके अलावा होता है।
हमने जो कुछ भी सीखा है, उसके आधार पर, हम यह निष्कर्ष निकाल सकते हैं कि आपको हर बार ऑब्जेक्ट में किसी भी बदलाव के साथ सर्वर कॉल करने की आवश्यकता नहीं है। उदाहरण के लिए, आप ऑब्जेक्ट में परिवर्तन जमा कर सकते हैं और फिर एक बार सर्वर भाग को कॉल कर सकते हैं और सभी परिवर्तन सही ढंग से किए और संसाधित किए जाएंगे।
चरण 1: डोमेन सेवा में डेटा अपडेट विधि जोड़ें।
पहले पाठ में, एक डोमेन सेवा बनाते समय, हमने निर्माण विज़ार्ड का उपयोग किया। और यदि आप "एडिटिंग एडिट" कॉलम में प्रत्येक इकाई के आगे वाले बॉक्स को चेक करते हैं, तो हमें प्रत्येक इकाई के लिए स्वचालित रूप से उत्पन्न तरीके मिलेंगे जो CRUD कार्यक्षमता को कार्यान्वित करते हैं।

कोड इस तरह दिखेगा:
public void InsertTask(Task task) { if ((task.EntityState != EntityState.Detached)) { this.ObjectContext.ObjectStateManager.ChangeObjectState(task, EntityState.Added); } else { this.ObjectContext.Tasks.AddObject(task); } } public void UpdateTask(Task currentTask) { this.ObjectContext.Tasks.AttachAsModified(currentTask, this.ChangeSet.GetOriginal(currentTask)); } public void DeleteTask(Task task) { if ((task.EntityState == EntityState.Detached)) { this.ObjectContext.Tasks.Attach(task); } this.ObjectContext.Tasks.DeleteObject(task); }
ये विधियाँ संबंधित इकाई ढांचे के संचालन पर सरल आवरण हैं।
चरण 2: नए कार्यों के लिए UI में तत्वों को जोड़ना
दो बटन जोड़ें जो एक नया कार्य जोड़ देगा और डेटाबेस में परिवर्तित संग्रह को बचाएगा।
<Button Name="addTaskButton" Content="Add Task" Click="addTaskButton_Click" .../> <Button Name="saveChangesButton" Content="Save Changes" Click="saveChangesButton_Click" .../>

चरण 3: एक नया कार्य बनाएं, इसे डोमेन संदर्भ में जोड़ें और परिवर्तनों को सहेजें।
क्रमशः नए बटनों के "क्लिक" ईवेंट हैंडलर में निम्न कोड जोड़ें:
TasksDomainContext context = new TasksDomainContext(); private void addTaskButton_Click(object sender, RoutedEventArgs e) { taskDataGrid.ItemsSource = context.Tasks; context.Load(context.GetTasksQuery()); Task newTask = new Task { TaskName = "Deploy app", Description = "Deploy app to all servers in data center", StartDate = DateTime.Today, EndDate = DateTime.Today + TimeSpan.FromDays(7) }; context.Tasks.Add(newTask); } private void saveChangesButton_Click(object sender, RoutedEventArgs e) { context.SubmitChanges(); }
सबसे पहले, एक चर जोड़ा जाता है जिससे डोमेन संदर्भ जुड़ा हुआ है। जैसा कि पहले उल्लेख किया गया है, डोमेन संदर्भ को इतने लंबे समय तक रहना चाहिए कि यह परिवर्तनों को ट्रैक कर सके और उन्हें एप्लिकेशन के सर्वर साइड पर उपयुक्त विधि से कॉल करके लागू कर सके। इसलिए, हमने अपनी वस्तु में परिवर्तन जोड़ने और इन परिवर्तनों को बचाने के लिए विधि कॉल को अलग किया।
"टास्क जोड़ें" बटन पर क्लिक करने के बाद, इसका हैंडलर डोमेनडेटा स्रोत को बदलने के लिए हमारे डेटाग्रिड के आइटम स्रोत को बदल देता है, जिसे हमने पहले पाठ में जोड़ा था। तब डोमेन लोड को वांछित इकाई से भरने के लिए "लोड" विधि कहा जाता है।
इसके बाद, एक नया कार्य ऑब्जेक्ट बनाएं और पॉप्युलेट करें और इसे कार्य डोमेन संदर्भ संग्रह में जोड़ें। इन परिवर्तनों को तुरंत यूआई में परिलक्षित किया जाएगा, क्योंकि उल्लिखित संग्रह INotifyCollectionChanged इंटरफ़ेस को लागू करता है। लेकिन, ध्यान रखें कि इन सभी परिवर्तनों को डोमेन संदर्भ कैश में लागू, प्रदर्शित और संग्रहीत किया गया है। लेकिन वे सर्वर की ओर और डेटाबेस में नहीं बदले गए। परिवर्तनों को लागू करने के लिए, आपको SubmitChanges विधि को कॉल करना होगा, जिसे तब कहा जाता है जब आप हमारे एप्लिकेशन के संबंधित बटन पर क्लिक करते हैं।
जब आप "टास्क जोड़ें" बटन पर क्लिक करते हैं, तो आप देखेंगे कि एक नया कार्य जोड़ा गया है, लेकिन "टास्कआईड" फ़ील्ड में मान हमेशा "0" होंगे। हालाँकि, यदि आप "SubmitChanges" बटन पर क्लिक करते हैं, तो थोड़ी देर के बाद, अतुल्यकालिक कॉल होने के बाद, एक अनुरोध निष्पादित किया जाएगा और डेटा अपडेट किया जाएगा और प्रासंगिक हो जाएगा।
अतुल्यकालिक डोमेन संदर्भ एपीआई
मैंने पहले ही इसका उल्लेख किया था, लेकिन मैं फिर से दोहराता हूं। डोमेन संदर्भ एपीआई के "लोड" और "SubmitChanges" जैसे तरीके अतुल्यकालिक रूप से लागू होते हैं। इसका मतलब है कि वे उस थ्रेड के काम को रोकते नहीं हैं जो उन्हें कॉल करता है, जिसमें यूआई आमतौर पर स्थित होता है। वे थ्रेड पूल "पर्दे के पीछे" से एक धागा लेते हैं, पृष्ठभूमि में एक सर्वर कॉल करते हैं, और जब कॉल पूरा हो जाता है, तो कॉलिंग यूआई थ्रेड पर वापस लौटकर इकाई संग्रह और यूआई को अपडेट करें।
यह सब आसान और सुंदर है। जब यह काम करता है। लेकिन वास्तव में मरहम में हमेशा एक मक्खी होती है। संचार समस्याएं हैं, या किसी ने गलती से कनेक्शन स्ट्रिंग को खराब कर दिया है, या पृष्ठभूमि में समानांतर संघर्ष हैं। लेकिन सभी संभावित परिदृश्यों के बावजूद, यह जानने की आवश्यकता है कि चुनौतियां कब पूरी हुईं और कब आपको आगे बढ़ने का अवसर प्रदान करना है, गायब न हों। ऐसा करने के कुछ तरीके हैं: वापसी प्रकार या कॉलबैक का उपयोग करें, जिसे ऑपरेशन पूरा होने पर कहा जाएगा।
पहला विकल्प असिंक्रोनसली विधि से रिटर्न वैल्यू के साथ काम करना है। लोड विधि एक LoadOperation लौटाता है, और SubmitChanges विधि एक SubmitOperation लौटाता है। वे दोनों ऑपरेशनबेस विरासत में लेते हैं और इसलिए ऑपरेशन के बारे में पर्याप्त जानकारी प्रदान करते हैं, जिसका उपयोग आप ऑपरेशन के दौरान या ऑपरेशन पूरा होने के बाद कर सकते हैं। वे ऑपरेशन के अंत में "पूर्ण" घटना को भी ट्रिगर करते हैं, और स्वाभाविक रूप से आपके पास इस घटना की सदस्यता लेने का अवसर होता है। बेशक, विभिन्न त्रुटियां, विभिन्न झंडे का संचालन, और बहुत कुछ जो कि एप्लिकेशन बनाने के लिए उपयोग किया जा सकता है उपलब्ध हैं।
"पूर्ण" ईवेंट की सदस्यता लेने के विकल्प के रूप में, आप कॉल को ओवरलोड "लोड" या "SubmitChanges" विधि में उपयोग कर सकते हैं, जो क्रमशः एक्शन और एक्शन लौटाते हैं। कॉलबैक फ़ंक्शन के लिंक को पास करें, और जब ऑपरेशन पूरा हो जाता है, तो इसे स्वचालित रूप से कहा जाता है।
इस ट्यूटोरियल के लिए वीडियो
स्रोत कोड
गीथूब पर