यदि आधुनिक ORM (EF, nHibernate) के लिए रिपॉजिटरी पैटर्न ओवरकिल है, तो एक बेहतर अमूर्तता क्या है?


12

मैंने हाल ही में शक्तिशाली ओआरएम जैसे एंटिटी फ्रेमवर्क के साथ रिपॉजिटरी पैटर्न का उपयोग करने के खिलाफ बहुत सारे तर्क पढ़े हैं क्योंकि इसमें रिपोजिटरी जैसी कार्यक्षमता शामिल है, साथ ही यूनिट की कार्य कार्यक्षमता भी शामिल है।

इकाई परीक्षण जैसी स्थिति के लिए पैटर्न का उपयोग करने के खिलाफ एक और तर्क यह है कि रिपॉजिटरी पैटर्न एक लीक से हटकर है क्योंकि अधिक सामान्य कार्यान्वयन IQueryable का लाभ उठाते हैं।

रिपॉजिटरी पैटर्न का उपयोग करने के खिलाफ तर्क मेरे लिए मायने रखते हैं, लेकिन सुझाए गए सार के वैकल्पिक तरीके अक्सर अधिक भ्रमित होते हैं और समस्या के रूप में ओवरकिल के रूप में दिखाई देते हैं।

जिमी बोगार्ड्स समाधान अमूर्त को उड़ाने का मिश्रण लगता है, लेकिन यह भी अपनी खुद की वास्तुकला का परिचय दे रहा है। https://lostechies.com/jimmybogard/2012/10/08/favor-query-objects-over-repositories/

अनावश्यक रूप से रिपोजिटरी का एक और उदाहरण .... लेकिन मेरी वास्तुकला का उपयोग करें! http://blog.gauffin.org/2012/10/22/griffin-decoupled-the-queries/

एक और ... http://www.thereformedprogrammer.net/is-the-repository-pattern-useful-with-entity-framework

मुझे "ओवरली कॉम्प्लेक्स" रिपॉजिटरी पैटर्न दृष्टिकोण के लिए एक स्पष्ट प्रतिस्थापन या विकल्प नहीं मिला है जो स्वयं अधिक आर्किटेक्चर नहीं है।


4
क्या आप विशेष रूप से प्राप्त करने की कोशिश कर रहे हैं? अंशों का एक उद्देश्य होना चाहिए। यदि आप एक CRUD ऐप लिख रहे हैं तो संभवतः एक ORM पर्याप्त है।
जैक्सबी

@JacquesB मैं एक मजबूत डोमेन मॉडल के साथ वस्तु संबंधपरक प्रतिबाधा के मुद्दों से बचने की कोशिश कर रहा हूं, लेकिन यह भी सार है कि एक mvc कार्यान्वयन में मेरे viewmodels से दूर।
डिवेलप्टर

रीड कॉस्पे में IQuerable के बारे में कहने के लिए बहुत सारी सकारात्मक बातें हैं: stackoverflow.com/questions/1578778/use-iqueryable-with-linq इसका मतलब है कि यह परिवहन परत पर बेहतर है। जहां तक ​​अमूर्तता की बात है, तो मुझे EntityType को इंजेक्ट करने के लिए जेनेरिक रिपॉजिटरी पैटर्न के काम के लिए अच्छा उपयोग मिला, लेकिन फिर भी मैं सामान्य तरीकों को बनाए रखना चाहता था। दूसरी ओर, मैंने खुद MSDN LINQ फोरम पर तर्क दिया है कि EF एक रिपॉजिटरी पैटर्न है क्योंकि यह सभी मेमोरी में है। एक परियोजना ने कई कॉल का उपयोग किया जहां विधि कॉल के रूप में क्लॉस होता है जो अच्छी तरह से काम करता है।
जॉन पीटर्स

लेकिन एक क्षेत्र जिसे मैंने देखा था लेकिन अस्वीकार कर दिया गया था अभिव्यक्ति वृक्ष का व्यवसाय, कुछ वास्तव में इसे पसंद करते हैं, लेकिन .... आपको इसे उपयोगी खोजने से पहले कठिन अध्ययन करना होगा।
जॉन पीटर्स

2
हमें कंट्रोलर्स से SQL कॉलिंग पर वापस जाना चाहिए
bobek

जवाबों:


12

मुझे लगता है कि आप रिपॉजिटरी और जेनेरिक रिपॉजिटरी का सामना कर रहे हैं।

एक बेसिक रिपॉजिटरी सिर्फ आपके डेटा स्टोर को बाधित करती है और डेटा को वापस करने के तरीके प्रदान करती है

IRepository {
   List<Data> GetDataById(string id);
}

यह IQueryable या यादृच्छिक प्रश्नों में उत्तीर्ण होने के अन्य तरीकों से आपके कोड में डेटा लेयर को लीक नहीं करता है और तरीकों की एक अच्छी तरह से परिभाषित परीक्षण योग्य और इंजेक्टेबल सतह प्रदान करता है।

एक सामान्य रिपॉजिटरी आपको एक ORM की तरह अपनी क्वेरी में पारित करने की अनुमति देती है

IGenericRepository<T> {
    List<T> Get<T>(IQuery query);
    //or
    IQueryable<T> Get<T>();
}

मैं मानता हूं कि ओआरएम के शीर्ष पर जेनेरिक रिपॉजिटरी का उपयोग करने के लिए बहुत अधिक बिंदु नहीं है जो मूल रूप से सिर्फ एक और जेनेरिक रिपॉजिटरी है।

इसका उत्तर अपने ओआरएम को छिपाने के लिए मूल रिपोजिटरी पैटर्न का उपयोग करना है


1
एक ORM का एक ORM? मैं मजाकिया बनने की कोशिश कर रहा था। आपको ओआरएम को अमूर्त करने की आवश्यकता क्यों है?
जॉनी

1
इसी कारण से आप कुछ भी सार करते हैं। मालिकाना वर्गों के साथ अपने कोड को प्रदूषित करने से बचने के लिए
इवान

6

अधिकांश तर्क आप गलत तरीके से रिपॉजिटरी पैटर्न विशेषताओं का उल्लेख करते हैं, जो इसमें नहीं है।

वैचारिक रूप से, डीडीडी में मूल रूप से परिभाषित एक रिपॉजिटरी केवल उन वस्तुओं का एक संग्रह है जिन्हें आप खोज सकते हैं या जोड़ सकते हैं। इसके पीछे हठ तंत्र अमूर्त है, इसलिए एक उपभोक्ता के रूप में आपको भ्रम हो जाता है कि यह इन-मेमोरी संग्रह है।

एक रिपॉजिटरी कार्यान्वयन जिसमें टपका हुआ सार है ( IQueryablesउदाहरण के लिए उजागर करना) एक खराब रिपॉजिटरी कार्यान्वयन है।

एक रिपॉजिटरी कार्यान्वयन जो केवल संग्रह संचालन (उदाहरण के लिए, कार्य सुविधाओं की इकाई) से अधिक को उजागर करता है, एक खराब रिपॉजिटरी कार्यान्वयन है।

क्या डेटा एक्सेस के लिए रिपॉजिटरी के विकल्प हैं? हां, लेकिन वे उन मुद्दों से संबंधित नहीं हैं जिन्हें आप अपने प्रश्न में लाते हैं।



1

मेरे लिए, रिपॉजिटरी, ORM या अन्य DB दृढ़ता परतों के साथ संयुक्त, इन नुकसान हैं:

  1. कार्य की इकाइयों को कवर करना। यूओडब्ल्यू को प्रोग्रामर द्वारा कोड किया जाना है और इसे शायद ही कभी पृष्ठभूमि में एक तरह के जादू के रूप में लागू किया जा सकता है, जहां उपयोगकर्ता यूओडब्ल्यू सीमाओं और संभवतः प्रतिबद्ध बिंदु को परिभाषित किए बिना, केवल प्रश्न और संशोधन करता है। कभी-कभी, प्रत्येक रिपॉजिटरी एक्सेस पद्धति में यूओडब्ल्यू को माइक्रो यूओडब्ल्यू (जैसे NHibernate सत्र) में कम करके छोड़ दिया जाता है।
  2. कवर करना, या, सबसे खराब स्थिति में, दृढ़ता अज्ञान को नष्ट करना: "लोड ()", "जाओ ()", "सहेजें ()" या "अपडेट ()" जैसे तरीके तत्काल, एकल वस्तु संचालन का सुझाव देते हैं, जैसे कि व्यक्तिगत भेजना एसक्यूएल / डीएमएल, या यदि फ़ाइलों के साथ काम कर रहे हैं। वास्तव में, उदाहरण के लिए, NHibernate तरीके, इन भ्रामक नामों के साथ, आमतौर पर व्यक्तिगत पहुंच नहीं बनाते हैं, लेकिन आलसी लोड या डालने / अपडेट बैच (पर्सिस्टेंस इग्नोरेंस) के लिए एन्क्यू। कभी-कभी, प्रोग्रामर आश्चर्यचकित होते हैं कि उन्हें तत्काल डीबी संचालन क्यों नहीं मिलता है और जबरन दृढ़ता से अज्ञानता को तोड़ते हैं, इस प्रकार प्रदर्शन को मारते हैं और वास्तव में सिस्टम को बनाने के लिए बड़े प्रयासों का उपयोग करते हैं (बहुत!) बदतर।
  3. अनियंत्रित विकास। एक साधारण भंडार विशिष्ट आवश्यकताओं को पूरा करने के लिए अधिक से अधिक तरीकों को जमा कर सकता है।

जैसे कि:

public interface ICarsRepository  /* initial */
{
    ICar CreateNewCar();
    ICar LoadCar(int id); // bad, should be for multiple IDs.
    void SaveCar(ICar carToSave); // bad, no individual saves, use UoW commit!
}

public interface ICarsRepository  /* a few years later */
{
    ICar CreateNewCar();
    ICar LoadCar(int id); 
    IList<ICar> GetBlueCars();
    IList<ICar> GetRedYellowGreenCars();
    IList<ICar> GetCarsByColor(Color colorOfCars); // a bit better
    IList<ICar> GetCarsByColor(IEnumerable<Color> colorsOfCars); // better!
    IList<ICar> GetCarsWithPowerBetween(int hpFrom, int hpTo);
    IList<ICar> GetCarsWithPowerKwBetween(int kwFrom, int kwTo);
    IList<ICar> GetCarsBuiltBetween(int yearFrom, int yearTo);
    IList<ICar> GetCarsBuiltBetween(DateTime from, DateTime to); // some also need month and day
    IList<ICar> GetHybridCarsBuiltBetween(DateTime from, DateTime to); 
    IList<ICar> GetElectricCarsBuiltBetween(DateTime from, DateTime to); 
    IList<ICar> GetCarsFromManufacturer(IManufacturer carManufacturer); 
    bool HasCarMeanwhileBeenChangedBySomebodyElseInDb(ICar car); // persistence ignorance broken
    void SaveCar(ICar carToSave);
}

4. ईश्वर की वस्तु का खतरा: आपको अपने सभी मॉडल या डेटा एक्सेस लेयर को कवर करते हुए, एक ईश्वर वर्ग बनाने का प्रलोभन दिया जा सकता है। रिपॉजिटरी क्लास में न केवल कार के तरीके होंगे, बल्कि सभी संस्थाओं के लिए तरीके होंगे।

मेरी राय में, कई एकल उद्देश्य विधियों की भारी गड़बड़ी से बचने के लिए, कम से कम कुछ क्वेरी के अवसरों की पेशकश करना बेहतर है। कोई फर्क नहीं पड़ता कि यह LINQ है, एक स्वयं की क्वेरी भाषा, या यहां तक ​​कि ORM से सीधे कुछ लिया (ठीक है, युग्मन समस्या ...)।


4
यदि इन सभी विधियों का उपयोग नहीं किया जाता है, तो क्या कोई रिपॉजिटरी पैटर्न का उपयोग नहीं करता है?
जॉनी

@ जॉनी यहां आप जाएं: softwareengineering.stackexchange.com/a/220126/100617
lexeme

1

यदि रिपॉजिटरी-इंटरफ़ेस का उद्देश्य डेटाबेस को एक unittest (= अलगाव में परीक्षण) के लिए मॉक करना है, तो सबसे अच्छा अमूर्त एक ऐसी चीज़ है जो नकली करना आसान है।

यह एक रिपॉजिटरी इंटरफ़ेस को मॉक करने के लिए अलग है जो कि एक IQueryable परिणाम पर आधारित है।

एक इकाई-परीक्षण के दृष्टिकोण से

IRepository {
   List<Data> GetDataById(string id);
}

आसानी से मजाक किया जा सकता है

IGenericRepository<T> {
    List<T> Get<T>(IQuery query);
}

मॉक को केवल तभी आसान किया जा सकता है जब मॉक क्वेरी पैरामीटर की सामग्री को अनदेखा करता है।

IGenericRepository<T> {
    IQueryable<T> Get<T>(some_parameters);
}

आसानी से मजाक नहीं किया जा सकता


0

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

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

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        UserRepository ur = new UserRepository();
        var userWithA = ur.GetBy(u => u.Name.StartsWith("A"));

        Console.WriteLine(userWithA.Name);


        ur.GetAllBy(u => u.Name.StartsWith("M"))
          .ForEach(u => Console.WriteLine(u.Name));


        ur.GetAllBy(u => u.Age > 13)
          .ForEach(u => Console.WriteLine(u.Name));
    }
}

public class UserRepository 
{
    List<User> users = new List<User> { 
        new User{Name="Joe", Age=10},
            new User{Name="Allen", Age=12},
            new User{Name="Martin", Age=14},
            new User{Name="Mary", Age=15},
            new User{Name="Ashton", Age=29}
    };

    public User GetBy(Predicate<User> userPredicate)
    {
        return users.Find(userPredicate);
    }

    public List<User> GetAllBy(Predicate<User> userPredicate)
    {
        return users.FindAll(userPredicate);
    }
}

public class User
{
    public string Name { get; set; }

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