CRUD API: आप किस क्षेत्र को अद्यतन करने के लिए निर्दिष्ट करते हैं?


9

मान लें कि आपके पास कुछ प्रकार की डेटा संरचना है, जो किसी प्रकार के डेटाबेस में बनी रहती है। सरलता के लिए, आइए इस डेटा संरचना को कॉल करें Person। अब आपको एक CRUD API डिज़ाइन करने का काम सौंपा गया है, जो अन्य एप्लिकेशन को s बनाने, पढ़ने, अपडेट करने और डिलीट करने की अनुमति देता है Person। सरलता के लिए, मान लेते हैं कि यह API किसी प्रकार की वेब सेवा के माध्यम से एक्सेस किया गया है।

सीआरयूडी के सी, आर और डी भागों के लिए, डिजाइन सरल है। मैं C # की तरह कार्यात्मक संकेतन का उपयोग करूंगा - कार्यान्वयन SOAP, REST / JSON, या कुछ और हो सकता है:

class Person {
    string Name;
    DateTime? DateOfBirth;
    ...
}

Identifier CreatePerson(Person);
Person GetPerson(Identifier);
void DeletePerson(Identifier);

अपडेट के बारे में क्या? करने के लिए स्वाभाविक बात होगी

void UpdatePerson(Identifier, Person);

लेकिन आप यह कैसे निर्दिष्ट करेंगे कि कौन से क्षेत्र Personअपडेट करें?


समाधान है कि मैं के साथ आ सकता है:

  • आपको हमेशा एक पूर्ण व्यक्ति को पारित करने की आवश्यकता हो सकती है, अर्थात ग्राहक जन्म तिथि को अद्यतन करने के लिए कुछ इस तरह करेगा:

    p = GetPerson(id);
    p.DateOfBirth = ...;
    UpdatePerson(id, p);
    

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

    UpdatePerson(id, { "DateOfBirth": "2015-01-01" });
    

    - जो सही दिखता है - वह न केवल DateOfBirth को बदल देगा, बल्कि अन्य सभी फ़ील्ड्स को शून्य करने के लिए रीसेट कर देगा।

  • आप सभी क्षेत्रों की उपेक्षा कर सकते हैं null। हालाँकि, आप तब कैसे नहीं बदलने DateOfBirth और जानबूझकर इसे शून्य में बदलने के बीच अंतर करेंगे ?

  • हस्ताक्षर को बदलें void UpdatePerson(Identifier, Person, ListOfFieldNamesToUpdate)

  • हस्ताक्षर को बदलें void UpdatePerson(Identifier, ListOfFieldValuePairs)

  • ट्रांसमिशन प्रोटोकॉल की कुछ विशेषता का उपयोग करें: उदाहरण के लिए, आप सभी क्षेत्रों को अनदेखा कर सकते हैं जो व्यक्ति के JSON प्रतिनिधित्व में निहित नहीं हैं। हालाँकि, आमतौर पर JSON को स्वयं पार्स करने की आवश्यकता होती है और आपकी लाइब्रेरी की अंतर्निहित सुविधाओं (जैसे WCF) का उपयोग करने में सक्षम नहीं होता है।

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


व्यक्ति का पहचानकर्ता हिस्सा क्यों नहीं है? नए बनाए गए Personउदाहरणों के लिए जो अभी भी कायम नहीं हैं, और मामले में पहचानकर्ता को दृढ़ता तंत्र के हिस्से के रूप में तय किया जाता है, बस इसे शून्य करने के लिए छोड़ दें। जवाब के लिए, जेपीए एक संस्करण संख्या का उपयोग करता है; यदि आप संस्करण 23 को पढ़ते हैं, जब आप आइटम को अपडेट करते हैं यदि DB में संस्करण 24 है तो लेखन विफल हो जाता है।
SJuan76

अनुमति दें और दोनों संवाद PUTऔर PATCHतरीकों। उपयोग करते समय PATCH, केवल चाबियाँ भेजनी चाहिए, PUTपूरे ऑब्जेक्ट को बदल दिया जाना चाहिए ।
लोड

जवाबों:


8

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

यदि आपके पास गतिविधि ट्रैकिंग आवश्यकता है। आपकी दुनिया बहुत अधिक जटिल है और आपको यह डिज़ाइन करने की आवश्यकता होगी कि CRUD क्रियाओं के बारे में जानकारी कैसे संग्रहीत करें और उन्हें कैसे इंटरसेप्ट करें। यह वह दुनिया है जिसमें आप ऐसा नहीं करना चाहते हैं यदि आपके पास ऐसी आवश्यकता नहीं है।

अलग-अलग लेन-देन द्वारा मूल्यों को ओवरराइड करने के अनुसार, मैं आशावादी और निराशावादी लॉकिंग के आसपास अनुसंधान करने का सुझाव दूंगा । वे इस सामान्य परिदृश्य को कम करते हैं:

  1. ऑब्जेक्ट user1 द्वारा पढ़ा जाता है
  2. ऑब्जेक्ट को user2 द्वारा पढ़ा जाता है
  3. उपयोगकर्ता द्वारा लिखित वस्तु 1
  4. User2 द्वारा लिखी गई वस्तु और user1 द्वारा लिखित परिवर्तन

प्रत्येक उपयोगकर्ता के पास अलग-अलग लेनदेन होता है, इसलिए इसके साथ मानक एसक्यूएल। सबसे आम आशावादी लॉकिंग है (संस्करणों के बारे में टिप्पणी में @ एसजेयूएन 76 द्वारा भी उल्लेख किया गया है)। आपका संस्करण DB में आपका रिकॉर्ड और लिखने के दौरान आप पहले DB में एक नज़र डालते हैं यदि संस्करण मेल खाते हैं। यदि संस्करण मेल नहीं खाते हैं, तो आप जानते हैं कि किसी ने इस बीच ऑब्जेक्ट को अपडेट किया है, और आपको इस स्थिति के बारे में उपभोक्ता को त्रुटि संदेश के साथ प्रतिक्रिया करने की आवश्यकता है। हां, आपको इस स्थिति को उपयोगकर्ता को दिखाना होगा।

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

डेल्टा लॉजिक में डालना उपभोक्ता के साथ अनुबंध पर निर्भर करता है, लेकिन ध्यान दें कि उपभोक्ता के लिए सबसे आसान है डेल्टा के बजाय पूर्ण पेलोड का निर्माण करना।


2

हमारे पास काम पर एक PHP एपीआई है। अपडेट के लिए यदि कोई क्षेत्र JSON ऑब्जेक्ट में नहीं भेजा जाता है, तो वह NULL पर सेट हो जाता है। फिर यह संग्रहित प्रक्रिया के लिए सब कुछ गुजरता है। संग्रहीत कार्यविधि फ़ील्ड के साथ हर क्षेत्र को अपडेट करने का प्रयास करती है = IFNULL (इनपुट, फ़ील्ड)। इसलिए यदि JSON ऑब्जेक्ट में सिर्फ 1 फ़ील्ड है केवल उस फ़ील्ड को अपडेट किया गया है। एक सेट फ़ील्ड को स्पष्ट रूप से खाली करने के लिए हमारे पास फ़ील्ड = '' है, फिर DB खाली कॉलम या उस कॉलम के डिफ़ॉल्ट मान के साथ फ़ील्ड को अपडेट करता है।


3
आप कैसे जानबूझकर अशक्त करने के लिए एक क्षेत्र निर्धारित करते हैं जो पहले से ही अशक्त नहीं है?
रॉबर्ट हार्वे

सभी फ़ील्ड NULL सेट नहीं हैं, इसलिए CHAR फ़ील्ड्स डिफ़ॉल्ट रूप से '' प्राप्त करें और सभी पूर्णांक फ़ील्ड्स 0. प्राप्त करें
Jared Bernacchi

1

क्वेरी स्ट्रिंग में अद्यतन फ़ील्ड सूची निर्दिष्ट करें।

PUT /resource/:id?fields=name,address,dob Body { //resource body }

अनुरोध बॉडी से मॉडल के साथ मर्ज किए गए डेटा को लागू करें:

private ResourceModel MergeResourceModel(ResourceModel original, ResourceModel updated, List<string> fields)
{
    var comparer = new FieldComparer();

    foreach (
            var item in
            typeof (ResourceModel).GetProperties()
                    .Where(p => p.CustomAttributes.All(a => a.AttributeType != typeof (JsonIgnoreAttribute))))
    {
        if (fields.Contains(item.Name, comparer))
        {
            var property = typeof (ResourceModel).GetProperty(item.Name);
            property.SetValue(original, property.GetValue(updated));
        }
    }

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