POST क्रिया में मॉडल मॉडल को डोमेन मॉडल पर वापस मैप कैसे करें?


87

ViewModels का उपयोग करने और Automapper का उपयोग करने पर इंटरनेट में पाया गया प्रत्येक लेख "नियंत्रक -> दृश्य" दिशा मानचित्रण के दिशानिर्देश देता है। आप एक विशेष ViewModel में सभी चयन सूचियों के साथ एक डोमेन मॉडल लेते हैं और इसे दृश्य में पास करते हैं। यह स्पष्ट और ठीक है।
दृश्य का एक रूप है, और अंततः हम POST कार्रवाई में हैं। यहाँ सभी मॉडल बाइंडर्स दृश्य के साथ आते हैं [जाहिर है] एक और मॉडल देखें [स्पष्ट रूप से] मूल ViewModel से संबंधित है, कम से कम बाध्यकारी और मान्यता के लिए नामकरण सम्मेलनों के हिस्से में।

आप इसे अपने डोमेन मॉडल में कैसे मैप करते हैं?

इसे डालने की क्रिया होने दें, हम उसी ऑटोमेपर का उपयोग कर सकते हैं। लेकिन क्या होगा अगर यह एक अद्यतन कार्रवाई थी? हमें अपनी डोमेन इकाई को रिपॉजिटरी से पुनः प्राप्त करना होगा, यह देखें कि यह ViewModel में मान के अनुसार गुण है और रिपॉजिटरी में सहेजें।

ADDENDUM 1 (9 फरवरी 2010): कभी-कभी, मॉडल के गुणों को निर्दिष्ट करना पर्याप्त नहीं है। व्यू मॉडल के मूल्यों के अनुसार डोमेन मॉडल के खिलाफ कुछ कार्रवाई की जानी चाहिए। यानी, कुछ तरीकों को डोमेन मॉडल पर बुलाया जाना चाहिए। संभवतः, मॉडल सेवा को संसाधित करने के लिए एक तरह की एप्लिकेशन सेवा परत होनी चाहिए जो नियंत्रक और डोमेन के बीच में हो ...


इस कोड को कैसे व्यवस्थित करें और निम्नलिखित लक्ष्यों को प्राप्त करने के लिए इसे कहां रखें?

  • नियंत्रकों को पतला रखें
  • सम्मान SoC अभ्यास
  • डोमेन-चालित डिजाइन सिद्धांतों का पालन करें
  • हो जाओ
  • जारी ...

जवाबों:


37

मैं एक का उपयोग IBuilder इंटरफेस और का उपयोग कर इसे लागू ValueInjecter

public interface IBuilder<TEntity, TViewModel>
{
      TEntity BuildEntity(TViewModel viewModel);
      TViewModel BuildViewModel(TEntity entity);
      TViewModel RebuildViewModel(TViewModel viewModel); 
}

... (कार्यान्वयन) RebuildViewModel सिर्फ कॉल करता हैBuildViewModel(BuilEntity(viewModel))

[HttpPost]
public ActionResult Update(ViewModel model)
{
   if(!ModelState.IsValid)
    {
       return View(builder.RebuildViewModel(model);
    }

   service.SaveOrUpdate(builder.BuildEntity(model));
   return RedirectToAction("Index");
}

btw मैं ViewModel नहीं लिखता मैं लिखता हूँ इनपुट cuz यह बहुत छोटा है, लेकिन यह वास्तव में महत्वपूर्ण
आशा नहीं है कि यह मदद करता है

अपडेट: मैं इस दृष्टिकोण का उपयोग अब प्रॉडनर ASP.net MVC डेमो ऐप में कर रहा हूं , इसे अब IMapper कहा जाता है, यहां एक पीडीएफ भी दिया गया है जहां इस दृष्टिकोण को विस्तार से बताया गया है


मुझे यह तरीका पसंद है। एक बात जो मैं स्पष्ट नहीं कर रहा हूँ, हालांकि IBuilder का कार्यान्वयन, विशेष रूप से एक tiered अनुप्रयोग के प्रकाश में। उदाहरण के लिए, मेरे ViewModel में 3 SelectLists हैं। बिल्डर कार्यान्वयन रिपॉजिटरी से चयनित सूची मूल्यों को कैसे प्राप्त करता है?
मैट म्यूरल

@Matt Murrell prodinner.codeplex.com पर देखें। मैं वहां ऐसा करता हूं, और मैं इसे IBuilder के बजाय IMapper कहता हूं
Omu

6
मुझे यह तरीका पसंद है, मैंने इसका एक नमूना यहाँ लागू किया है: gist.github.com/2379583
पॉल स्टोवेल

मेरे दिमाग में यह डोमेन मॉडल दृष्टिकोण के अनुरूप नहीं है। यह अस्पष्ट आवश्यकताओं के लिए कुछ CRUD दृष्टिकोण की तरह दिखता है। क्या हमें कुछ उचित कार्रवाई करने के लिए डोमेन मॉडल में कारखानों (डीडीडी) और संबंधित तरीकों का उपयोग नहीं करना चाहिए? इस तरह हम DB से एक इकाई को बेहतर ढंग से लोड करेंगे और इसे आवश्यकतानुसार अपडेट करेंगे, है ना? तो ऐसा लगता है कि यह पूरी तरह से सही नहीं है।
Artyom

7

ऑटोमैपर जैसे उपकरण का उपयोग मौजूदा ऑब्जेक्ट को स्रोत ऑब्जेक्ट से डेटा के साथ अपडेट करने के लिए किया जा सकता है। अद्यतन करने के लिए नियंत्रक कार्रवाई की तरह लग सकता है:

[HttpPost]
public ActionResult Update(MyViewModel viewModel)
{
    MyDataModel dataModel = this.DataRepository.GetMyData(viewModel.Id);
    Mapper<MyViewModel, MyDataModel>(viewModel, dataModel);
    this.Repostitory.SaveMyData(dataModel);
    return View(viewModel);
}

ऊपर के स्निपेट में जो दिखाई दे रहा है उसके अलावा:

  • मॉडल + सत्यापन देखने के लिए POST डेटा ModelBinder में किया जाता है (कस्टम बाइंडिंग के साथ बढ़ाया जा सकता है)
  • त्रुटि से निपटने (यानी रिपॉजिटरी द्वारा डेटा एक्सेस अपवाद फेंकता है) [हैंडलेयर] फ़िल्टर द्वारा किया जा सकता है

नियंत्रक कार्रवाई बहुत पतली है और चिंताओं को अलग किया जाता है: ऑटोप्पर कॉन्फ़िगरेशन में मैपिंग मुद्दों को संबोधित किया जाता है, रिपॉजिटरी द्वारा मॉडलबाइंडर और डेटा एक्सेस द्वारा सत्यापन किया जाता है।


6
मुझे यकीन नहीं है कि ऑटोमैपर यहां उपयोगी है क्योंकि यह सपाट नहीं हो सकता है। आखिरकार, डोमेन मॉडल व्यू मॉडल की तरह एक सरल डीटीओ नहीं है, इसलिए यह कुछ गुणों को निर्दिष्ट करने के लिए पर्याप्त नहीं हो सकता है। संभवतः, दृश्य मॉडल की सामग्री के अनुसार डोमेन मॉडल के खिलाफ कुछ क्रियाएं की जानी चाहिए। हालांकि, काफी अच्छा तरीका साझा करने के लिए +1।
एंथोनी सेरड्यूकोव

@Anton ValueInjecter चपटे को उल्टा कर सकता है;)
ओमू

इस दृष्टिकोण के साथ आप नियंत्रक को पतला नहीं रखते हैं, आप SoC और DRY का उल्लंघन करते हैं ... जैसा कि ओमू ने उल्लेख किया है कि आपके पास एक अलग परत होनी चाहिए जो मैपिंग सामान की देखभाल करती है।
रूकियन

5

मैं कहना चाहूंगा कि आपने क्लाइंट इंटरैक्शन के दोनों दिशाओं के लिए ViewModel शब्द का पुन: उपयोग किया है। यदि आपने वाइल्ड में पर्याप्त ASP.NET MVC कोड पढ़ा है, तो आपने संभवतः ViewModel और EditMelel के बीच अंतर देखा है। मुझे लगता है कि यह महत्वपूर्ण है।

एक ViewModel एक दृश्य प्रस्तुत करने के लिए आवश्यक सभी जानकारी का प्रतिनिधित्व करता है। इसमें वह डेटा शामिल हो सकता है जो स्थिर गैर-संवादात्मक स्थानों में प्रदान किया गया हो और विशुद्ध रूप से डेटा प्रदान करने के लिए जाँच करने के लिए कि वास्तव में क्या करना है। एक नियंत्रक GET कार्रवाई आम तौर पर अपने दृश्य के लिए ViewModel की पैकेजिंग के लिए जिम्मेदार है।

एक EditModel (या शायद एक ActionModel) उस डेटा को प्रदर्शित करने के लिए आवश्यक कार्रवाई करता है जो उपयोगकर्ता उस POST के लिए करना चाहता था। तो एक EditModel वास्तव में एक कार्रवाई का वर्णन करने की कोशिश कर रहा है। यह संभवतः ViewModel के कुछ डेटा को बाहर कर देगा और यद्यपि संबंधित मुझे लगता है कि यह महसूस करना महत्वपूर्ण है कि वे वास्तव में अलग हैं।

एक विचार

कहा कि आप बहुत आसानी से मॉडल से जाने के लिए एक AutoMapper विन्यास हो सकता है -> ViewModel और एक अलग EditModel से जाने के लिए -> मॉडल। फिर विभिन्न नियंत्रक क्रियाओं को बस AutoMapper का उपयोग करने की आवश्यकता है। एडमेलमॉडल उस पर कार्य कर सकता है, यह मॉडल के खिलाफ गुणों को मान्य करने के लिए और उन मूल्यों को स्वयं मॉडल पर लागू करने के लिए हो सकता है। यह और कुछ नहीं कर रहा है और आपके पास अनुरोध को EditModel में मैप करने के लिए MVC में मॉडलबिंडर है।

एक अन्य विचार

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

अनिवार्य रूप से जैसे ही उपयोगकर्ता आपके द्वारा प्रस्तुत स्क्रीन पर कार्य करता है, जावास्क्रिप्ट कार्रवाई की वस्तुओं की एक सूची बनाना शुरू कर देगा। एक उदाहरण संभवतः उपयोगकर्ता एक कर्मचारी सूचना स्क्रीन पर है। वे अंतिम नाम को अपडेट करते हैं और एक नया पता जोड़ते हैं क्योंकि कर्मचारी की हाल ही में शादी हुई है। कवर के तहत यह एक ChangeEmployeeNameऔर एक का उत्पादन करता हैAddEmployeeMailingAddress एक सूची में वस्तुओं का । उपयोगकर्ता परिवर्तनों को करने के लिए 'सहेजें' पर क्लिक करता है और आप दो वस्तुओं की सूची जमा करते हैं, जिनमें से प्रत्येक में प्रत्येक कार्रवाई करने के लिए आवश्यक जानकारी होती है।

आपको एक अधिक बुद्धिमान ModelBinder की आवश्यकता होगी तब डिफ़ॉल्ट एक लेकिन अच्छा JSON सीरियलाइज़र सर्वर साइड वालों को क्लाइंट साइड एक्शन ऑब्जेक्ट्स की मैपिंग का ध्यान रखने में सक्षम होना चाहिए। सर्वर साइड वाले (यदि आप 2-स्तरीय वातावरण में हैं) आसानी से वे तरीके हो सकते हैं जो उस मॉडल पर कार्रवाई पूरी करते हैं जिसके साथ वे काम करते हैं। इसलिए नियंत्रक क्रिया को समाप्त करने के लिए मॉडल उदाहरण के लिए एक आईडी प्राप्त करना और उस पर प्रदर्शन करने के लिए क्रियाओं की एक सूची समाप्त हो जाती है। या कार्यों में उन्हें बहुत अलग रखने के लिए आईडी है।

तो शायद सर्वर साइड में ऐसा कुछ महसूस होता है:

public interface IUserAction<TModel>
{
     long ModelId { get; set; }
     IEnumerable<string> Validate(TModel model);
     void Complete(TModel model);
}

[Transaction] //just assuming some sort of 2-tier with transactions handled by filter
public ActionResult Save(IEnumerable<IUserAction<Employee>> actions)
{
     var errors = new List<string>();
     foreach( var action in actions ) 
     {
         // relying on ORM's identity map to prevent multiple database hits
         var employee = _employeeRepository.Get(action.ModelId);
         errors.AddRange(action.Validate(employee));
     }

     // handle error cases possibly rendering view with them

     foreach( var action in editModel.UserActions )
     {
         var employee = _employeeRepository.Get(action.ModelId);
         action.Complete(employee);
         // against relying on ORMs ability to properly generate SQL and batch changes
         _employeeRepository.Update(employee);
     }

     // render the success view
}

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

यदि आप 3 स्तरीय वातावरण में थे, तो IUserAction को सीमा के पार गोली मारने के लिए सरल DTO बनाया जा सकता है और ऐप लेयर पर एक समान विधि में प्रदर्शन किया जा सकता है। इस बात पर निर्भर करता है कि आप उस परत को कैसे करते हैं और इसे आसानी से विभाजित किया जा सकता है और फिर भी एक लेन-देन में बना रहता है (जो मन में आता है वह है अगाथा का अनुरोध / प्रतिक्रिया और डीआई और एनएचबर्नेट के पहचान मानचित्र का लाभ लेना)।

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


दिलचस्प। ViewModel और EditModel के बीच के अंतर के बारे में ... क्या आप सुसाइड कर रहे हैं कि एक एडिट फंक्शन के लिए आप फॉर्म बनाने के लिए एक ViewModel का उपयोग करेंगे, और तब एक EditModel से बंधेंगे जब उपयोगकर्ता इसे पोस्ट करेगा? यदि हां, तो आप उन परिस्थितियों से कैसे निपटेंगे, जहां आपको सत्यापन त्रुटियों के कारण फॉर्म को फिर से तैयार करना होगा (उदाहरण के लिए जब ViewModel में ड्रॉप डाउन को पॉप्युलेट करने के लिए तत्व शामिल थे) - क्या आप केवल EditModel में ड्रॉप डाउन तत्वों को भी शामिल करेंगे? किस मामले में, दोनों के बीच क्या अंतर होगा?
UpTheCreek

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

0

आपको डोमेन से व्यूमॉडल की मैपिंग करने की आवश्यकता नहीं है क्योंकि आपका व्यूमॉडल डोमेन मॉडल से अधिक बनाया जा सकता है। Viewmodels स्क्रीन (ui) के लिए अनुकूलित और डोमेन मॉडल से अलग है।

http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.