वेब अनुरोध प्रति एक DbContext ... क्यों?


398

मैं बहुत सारे लेख पढ़ रहा हूं, जिसमें बताया गया है कि एंटिटी फ्रेमवर्क कैसे सेट किया DbContextजाए ताकि विभिन्न डीआई फ्रेमवर्क का उपयोग करके HTTP वेब अनुरोध के अनुसार केवल एक ही बनाया और उपयोग किया जाए।

यह पहली जगह में एक अच्छा विचार क्यों है? इस दृष्टिकोण का उपयोग करके आपको क्या फायदे हैं? क्या कुछ ऐसी स्थितियाँ हैं जहाँ यह एक अच्छा विचार होगा? क्या ऐसी चीजें हैं जो आप इस तकनीक का उपयोग कर सकते हैं जो कि आप DbContextरिपॉजिटरी मेथड कॉल के प्रति इंस्टेंटेटिंग करते समय नहीं कर सकते हैं ?


9
Gueddari in mehdi.me/ambient-dbcontext-in-ef6 कॉल DbContext उदाहरण प्रति रिपोजिटरी विधि कॉल एक एंटीपैटर्न। उद्धरण: "ऐसा करने से, आप एंटिटी फ्रेमवर्क DbContext के माध्यम से अपने प्रथम स्तर के कैश, इसके पहचान मानचित्र, इसकी इकाई के कार्य और इसके परिवर्तन पर नज़र रखने और आलसी-लोडिंग क्षमताओं सहित बहुत अधिक हर सुविधा खो रहे हैं। । " DBContexts के जीवनचक्र को संभालने के लिए महान सुझावों के साथ उत्कृष्ट लेख। निश्चित रूप से पढ़ने लायक।
क्रिस्टोफ

जवाबों:


564

नोट: यह उत्तर एंटिटी फ्रेमवर्क के बारे में बात करता है DbContext, लेकिन यह किसी भी प्रकार के कार्य कार्यान्वयन के लिए लागू होता है, जैसे कि LINQ से SQL DataContextऔर NHibernate का ISession

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

मुझे यह कहने से शुरू करें कि एक DbContextक्षणिक के रूप में पंजीकरण करना काम कर सकता है, लेकिन आम तौर पर आप एक निश्चित दायरे में इस तरह की एक इकाई का एक ही उदाहरण रखना चाहते हैं। एक वेब एप्लिकेशन में, वेब अनुरोध की सीमाओं पर इस तरह के दायरे को परिभाषित करना व्यावहारिक हो सकता है; इस प्रकार प्रति वेब अनुरोध जीवन शैली। यह आपको एक ही संदर्भ में वस्तुओं का एक पूरा सेट संचालित करने देता है। दूसरे शब्दों में, वे एक ही व्यापार लेनदेन के भीतर काम करते हैं।

यदि आपके पास समान संदर्भ के अंदर संचालन का एक सेट होने का कोई लक्ष्य नहीं है, तो उस स्थिति में क्षणिक जीवनशैली ठीक है, लेकिन देखने के लिए कुछ चीजें हैं:

  • चूँकि हर वस्तु का अपना उदाहरण मिलता है, हर वर्ग जो सिस्टम की स्थिति को बदलता है, उसे कॉल करने की आवश्यकता होती है _context.SaveChanges()(अन्यथा परिवर्तन खो जाएगा)। यह आपके कोड को जटिल कर सकता है, और कोड के लिए एक दूसरी जिम्मेदारी (संदर्भ को नियंत्रित करने की जिम्मेदारी) को जोड़ता है, और एकल जिम्मेदारी सिद्धांत का उल्लंघन है ।
  • आपको यह सुनिश्चित करने की आवश्यकता है कि इकाइयाँ [द्वारा लोड और सहेजे गए DbContext] ऐसी श्रेणी का दायरा कभी नहीं छोड़तीं, क्योंकि उनका उपयोग किसी अन्य वर्ग के संदर्भ उदाहरण में नहीं किया जा सकता है। यह आपके कोड को बहुत जटिल कर सकता है, क्योंकि जब आपको उन संस्थाओं की आवश्यकता होती है, तो आपको उन्हें फिर से आईडी द्वारा लोड करने की आवश्यकता होती है, जिससे प्रदर्शन की समस्याएं भी हो सकती हैं।
  • DbContextलागू होने के बाद से IDisposable, आप शायद सभी बनाए गए उदाहरणों को निपटाना चाहते हैं। यदि आप ऐसा करना चाहते हैं, तो आपके पास मूल रूप से दो विकल्प हैं। आपको कॉल करने के ठीक बाद उन्हें उसी तरीके से निपटाने की आवश्यकता है context.SaveChanges(), लेकिन उस स्थिति में व्यावसायिक तर्क किसी ऐसी वस्तु का स्वामित्व लेता है जिसे वह बाहर से पास करता है। दूसरा विकल्प Http रिक्वेस्ट की सीमा पर सभी बनाए गए इंस्टेंस को डिस्पोज़ करना है, लेकिन उस स्थिति में भी आपको कंटेनर को यह बताने के लिए किसी प्रकार की स्कूपिंग की आवश्यकता होती है जब उन इंस्टेंसेस को डिस्पोज़ करने की आवश्यकता होती है।

एक अन्य विकल्प यह है कि बिल्कुल भी इंजेक्शन लगाएं DbContext। इसके बजाय, आप एक इंजेक्शन लगाते हैं जो DbContextFactoryएक नया उदाहरण बनाने में सक्षम होता है (मैं अतीत में इस दृष्टिकोण का उपयोग करता था)। इस तरह से व्यापार तर्क स्पष्ट रूप से संदर्भ को नियंत्रित करता है। अगर ऐसा दिख सकता है:

public void SomeOperation()
{
    using (var context = this.contextFactory.CreateNew())
    {
        var entities = this.otherDependency.Operate(
            context, "some value");

        context.Entities.InsertOnSubmit(entities);

        context.SaveChanges();
    }
}

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

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

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

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

कंटेनर और / या इंफ्रास्ट्रक्चर को संभालने से, आपके एप्लिकेशन कोड को बनाने के लिए प्रदूषित नहीं होता है, (वैकल्पिक रूप से) और एक यूओडब्ल्यू उदाहरण का निपटान करें, जो व्यापार तर्क को सरल और स्वच्छ रखता है (सिर्फ एक जिम्मेदारी)। इस दृष्टिकोण के साथ कुछ कठिनाइयाँ हैं। उदाहरण के लिए, क्या आप उदाहरण के लिए कमिट और डिस्पोज़ करते थे?

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

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

class TransactionalCommandHandlerDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    readonly DbContext context;
    readonly ICommandHandler<TCommand> decorated;

    public TransactionCommandHandlerDecorator(
        DbContext context,
        ICommandHandler<TCommand> decorated)
    {
        this.context = context;
        this.decorated = decorated;
    }

    public void Handle(TCommand command)
    {
        this.decorated.Handle(command);

        context.SaveChanges();
    } 
}

यह सुनिश्चित करता है कि आपको केवल एक बार इस इंफ्रास्ट्रक्चर कोड को लिखना होगा। कोई भी ठोस डीआई कंटेनर आपको इस तरह के डेकोरेटर को सभी ICommandHandler<T>कार्यान्वयन के चारों ओर एक सुसंगत तरीके से लपेटने के लिए कॉन्फ़िगर करने की अनुमति देता है।


2
वाह - पूरी तरह से उत्तर के लिए धन्यवाद। यदि मैं दो बार उत्थान कर सकता हूं, तो मैं करूंगा। ऊपर, आप कहते हैं "... एक ही संदर्भ के अंदर संचालन के पूरे सेट को संचालित करने का कोई इरादा नहीं है, उस स्थिति में क्षणिक जीवनशैली ठीक है ..."। विशेष रूप से "क्षणिक" से आपका क्या अभिप्राय है?
एंड्रयू

14
@Andrew: 'क्षणिक' एक डिपेंडेंसी इंजेक्शन अवधारणा है, जिसका अर्थ है कि यदि किसी सेवा को क्षणिक होने के लिए कॉन्फ़िगर किया गया है, तो सेवा का एक नया उदाहरण प्रत्येक बार उपभोक्ता में इंजेक्ट किए जाने पर बनाया जाता है।
स्टीवन

1
@ user981375: CRUD संचालन के लिए आप एक सामान्य CreateCommand<TEnity>और एक जेनेरिक बना सकते हैं CreateCommandHandler<TEntity> : ICommandHandler<CreateCommand<TEntity>>(और अपडेट के लिए भी ऐसा ही करें, और हटाएं, और एक ही GetByIdQuery<TEntity>क्वेरी थी)। फिर भी, आपको अपने आप से पूछना चाहिए कि क्या यह मॉडल CRUD संचालन के लिए एक उपयोगी अमूर्त है, या क्या यह सिर्फ जटिलता जोड़ता है। फिर भी, आप इस मॉडल का उपयोग करके आसानी से क्रॉस-कटिंग चिंताओं (सज्जाकारों के माध्यम से) को जोड़ने की संभावना से लाभान्वित हो सकते हैं। आपको पेशेवरों और विपक्षों का वजन करना होगा।
स्टीवन

3
+1 क्या आपको विश्वास होगा कि मैंने वास्तव में इसे पढ़ने से पहले इस उत्तर को लिखा था ? BTW IMO मुझे लगता है कि आपके लिए DbContext के निपटान पर चर्चा करना महत्वपूर्ण है (हालांकि इसके महान कि आप कंटेनर अज्ञेय रह रहे हैं)
Ruben Bartelink

1
लेकिन आप सजाए गए वर्ग के संदर्भ को पास नहीं करते हैं, सजाए गए वर्ग उसी संदर्भ के साथ कैसे काम कर सकते हैं जो पारित हुआ TransactionCommandHandlerDecorator? उदाहरण के लिए यदि सजाया गया वर्ग InsertCommandHandlerवर्ग है, तो वह संदर्भ में ऑपरेशन को कैसे दर्ज कर सकता है (DFContext EF में)?
मसूद

34

यहाँ एक भी उत्तर वास्तव में प्रश्न का उत्तर नहीं देता है। ओपी ने एक सिंगलटन / प्रति-एप्लिकेशन डीबोनक्स्ट डिज़ाइन के बारे में नहीं पूछा, उन्होंने प्रति (वेब) अनुरोध डिज़ाइन और क्या संभावित लाभ मौजूद हो सकते हैं, के बारे में पूछा।

मैं http://mehdi.me/ambient-dbcontext-in-ef6/ का संदर्भ लूंगा क्योंकि मेहदी एक शानदार संसाधन है:

संभावित प्रदर्शन लाभ।

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

यह आलसी-लोडिंग को सक्षम करता है।

यदि आपकी सेवाएँ लगातार इकाइयाँ लौटाती हैं (जैसा कि दृश्य मॉडल या DTO के अन्य प्रकारों को वापस करने के विरोध में) और आप उन संस्थाओं पर आलसी-लोडिंग का लाभ उठाना चाहते हैं, तो DbContext उदाहरण का जीवनकाल जिसमें से उन संस्थाओं को पुनः प्राप्त किया गया था, को आगे बढ़ाया जाना चाहिए व्यापार लेनदेन का दायरा। अगर सेवा पद्धति ने DbContext उदाहरण का उपयोग किया, तो लौटने से पहले इसका इस्तेमाल किया, लौटी संस्थाओं पर आलसी-लोड गुणों का कोई भी प्रयास विफल होगा (आलसी-लोडिंग का उपयोग करना या नहीं करना एक अच्छा विचार है एक अलग बहस पूरी तरह से है जो हम में नहीं मिलेगा यहाँ)। हमारे वेब एप्लिकेशन उदाहरण में, आलसी-लोडिंग का उपयोग आमतौर पर एक अलग सेवा परत द्वारा लौटी संस्थाओं पर नियंत्रक कार्रवाई विधियों में किया जाएगा। उस स्तिथि में,

ध्यान रखें कि विपक्ष भी हैं। उस लिंक में विषय पर पढ़ने के लिए कई अन्य संसाधन हैं।

बस इस मामले में किसी और को पोस्ट करने पर इस सवाल पर रोक लग जाती है और उन सवालों के जवाब में लीन नहीं होते हैं जो वास्तव में सवाल का जवाब नहीं देते हैं।


अच्छा लिंक! DBContext का प्रबंधन स्पष्ट रूप से सबसे सुरक्षित दृष्टिकोण की तरह दिखता है।
Aggsol

34

Microsoft द्वारा दो विरोधाभासी सिफारिशें हैं और कई लोग पूरी तरह से अलग तरीके से DbContexts का उपयोग करते हैं।

  1. एक सिफारिश है "DbContexts को जल्द से जल्द लागू करें" क्योंकि DbContext अलाइव के पास db कनेक्शन आदि जैसे बहुमूल्य संसाधन हैं।
  2. अन्य अनुरोधों के अनुसार प्रति DbContext अत्यधिक अनुमानित है

वे एक-दूसरे के विरोधाभासी हैं क्योंकि यदि आपका अनुरोध डीबी सामग्री से बहुत अधिक असंबंधित है, तो आपका डीबॉक्नेट बिना किसी कारण के रखा जाता है। इस प्रकार यह आपके DbContext को जीवित रखने के लिए बेकार है जबकि आपका अनुरोध बस यादृच्छिक सामान की प्रतीक्षा कर रहा है ...

नियम 1 का पालन करने वाले बहुत से लोग अपने "रिपोजिटरी पैटर्न" के अंदर अपना DbContexts रखते हैं और डेटाबेस क्वेरी के अनुसार एक नया इंस्टेंस बनाते हैं, इसलिए X * DbContext प्रति अनुरोध

वे बस अपना डेटा प्राप्त करते हैं और ASAP के संदर्भ का निपटान करते हैं। यह MANY लोगों द्वारा एक स्वीकार्य अभ्यास माना जाता है । हालांकि यह कम से कम समय में यह स्पष्ट रूप से बलिदान सभी के लिए अपने डाटाबेस संसाधनों पर कब्जा का लाभ मिलता है UnitOfWork और कैशिंग कैंडी एफई लिए प्रस्ताव दिया है।

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

इसलिए EF की टीम प्रति अनुरोध 1 डीबी संदर्भ का उपयोग करने के बारे में सिफारिश करती है यह स्पष्ट रूप से इस तथ्य पर आधारित है कि एक वेब अनुप्रयोग में एक यूनिटऑफवर्क सबसे अधिक संभावना एक अनुरोध के भीतर होने वाला है और उस अनुरोध का एक धागा है। तो प्रति अनुरोध एक DbContext UnitOfWork और कैशिंग के आदर्श लाभ की तरह है।

लेकिन कई मामलों में यह सच नहीं है। मैं एक अलग UnitOfWork लॉगिंग पर विचार करता हूं, इस तरह पोस्ट-रिक्वेस्ट के लिए एक नया DbContext होना, async थ्रेड्स में लॉगिंग पूरी तरह से स्वीकार्य है

तो अंत में यह ठुकरा दिया जाता है कि DbContext का जीवनकाल इन दो मापदंडों तक ही सीमित है। UnitOfWork और थ्रेड


3
सभी निष्पक्षता में, आपके HTTP अनुरोधों को जल्दी (कुछ एमएस) खत्म करना चाहिए। यदि वे इससे अधिक समय तक चल रहे हैं, तो आप बाहरी बैकग्राउंड शेड्यूलर जैसे कुछ के साथ कुछ पृष्ठभूमि प्रसंस्करण करने के बारे में सोचना चाह सकते हैं ताकि अनुरोध तुरंत वापस आ सके। उस ने कहा, आपकी वास्तुकला वास्तव में HTTP पर भी निर्भर नहीं होनी चाहिए। कुल मिलाकर, एक अच्छा जवाब है।
को

22

मुझे पूरा यकीन है कि यह इसलिए है क्योंकि DbContext सभी थ्रेड सुरक्षित नहीं है। इसलिए बात साझा करना कभी भी अच्छा विचार नहीं है।


क्या आप इसका मतलब है कि HTTP अनुरोधों को साझा करना एक अच्छा विचार नहीं है?
एंड्रयू

2
हाँ एंड्रयू thats वह क्या मतलब था। संदर्भ साझा करना केवल सिंगल थ्रेड डेस्कटॉप ऐप्स के लिए है।
एलिजाबेथ

10
एक अनुरोध के लिए संदर्भ साझा करने के बारे में क्या। तो एक निवेदन के लिए हम अलग-अलग रिपॉजिटरी तक पहुंच बना सकते हैं और एक ही संदर्भ को साझा करके उनके पार लेनदेन कर सकते हैं?
हुसोमिर वेलचेव

16

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

व्यक्तिगत रूप से मैं जरूरत पड़ने पर DbContext के उदाहरण बनाता हूं - आमतौर पर उन व्यावसायिक घटकों से जुड़ा होता है जो आवश्यकता पड़ने पर संदर्भ को फिर से बनाने की क्षमता रखते हैं। इस तरह मेरा उस प्रक्रिया पर नियंत्रण है, बजाय मुझ पर एक भी उदाहरण के मजबूर होने का। मुझे प्रत्येक नियंत्रक स्टार्टअप पर DbContext बनाने की आवश्यकता नहीं है, भले ही यह वास्तव में उपयोग हो। फिर अगर मैं अभी भी प्रति अनुरोध उदाहरणों के लिए चाहता हूं तो मैं उन्हें सीटीआर (डीआई या मैन्युअल रूप से) में बना सकता हूं या उन्हें प्रत्येक नियंत्रक पद्धति में आवश्यकतानुसार बना सकता हूं। व्यक्तिगत रूप से मैं आमतौर पर बाद के दृष्टिकोण के रूप में DbContext उदाहरण बनाने से बचने के लिए जब वे वास्तव में जरूरत नहीं है।

यह निर्भर करता है कि आप इसे किस कोण से देखते हैं। मेरे लिए प्रति अनुरोध उदाहरण कभी भी समझ में नहीं आया है। क्या DbContext वास्तव में Http Request में है? व्यवहार के मामले में यह गलत जगह है। आपके व्यावसायिक घटकों को आपके संदर्भ का निर्माण करना चाहिए, न कि Http के अनुरोध पर। फिर आप अपने व्यावसायिक घटकों को आवश्यकतानुसार बना या फेंक सकते हैं और संदर्भ के जीवनकाल के बारे में कभी चिंता न करें।


1
यह एक दिलचस्प जवाब है और मैं आपसे आंशिक रूप से सहमत हूं। मेरे लिए, एक DbContext को वेब अनुरोध से बंधा नहीं होना चाहिए, लेकिन यह हमेशा एक ही 'अनुरोध' में टाइप किया जाता है: जैसे 'व्यापार लेनदेन'। और जब आप किसी व्यावसायिक लेन-देन के संदर्भ को टाई करते हैं, तो परिवर्तन रद्द करना वास्तव में अजीब हो जाता है। लेकिन यह वेब अनुरोध सीमा पर नहीं होने का मतलब यह नहीं है कि व्यापारिक घटकों (बीसी) को संदर्भ बनाना चाहिए; मुझे लगता है कि यह उनकी जिम्मेदारी नहीं है। इसके बजाय, आप अपने बीसी के आसपास डेकोरेटर का उपयोग करके स्कूपिंग लगा सकते हैं। इस तरह आप बिना किसी कोड परिवर्तन के भी स्कूपिंग को बदल सकते हैं।
स्टीवन

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

संक्षेप में, जब आप कहते हैं कि "यदि आवश्यक हो तो संदर्भ को फिर से बनाने की क्षमता" का क्या मतलब है? क्या आप अपनी स्वयं की रोलबैक क्षमता को रोल कर रहे हैं? क्या आप एक टैड को विस्तृत कर सकते हैं?
tntwyckoff

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

इस सवाल का यह है कि क्या आप कंटेनर को dbcontext के जीवनकाल को नियंत्रित करने की अनुमति देते हैं जो कभी-कभी माता-पिता के जीवनकाल को नियंत्रित करता है, कभी-कभी अवांछित। कहो कि अगर मुझे अपने नियंत्रकों में एक साधारण सेवा के एकल का इंजेक्शन चाहिए तो मैं अनुरोधात्मक मनोदशा के कारण कंसीलर इंजेक्शन का उपयोग नहीं कर पाऊंगा।
davidcarr

10

मैं पिछली राय से सहमत हूं। यह कहना अच्छा है, कि यदि आप DbContext को सिंगल थ्रेड ऐप में साझा करने जा रहे हैं, तो आपको अधिक मेमोरी की आवश्यकता होगी। उदाहरण के लिए Azure (एक अतिरिक्त छोटा उदाहरण) पर मेरे वेब एप्लिकेशन को एक और 150 एमबी मेमोरी की आवश्यकता है और मेरे पास प्रति घंटे लगभग 30 उपयोगकर्ता हैं। HTTP रिक्वेस्ट में एप्लिकेशन शेयरिंग DBContext

यहां वास्तविक उदाहरण छवि है: आवेदन 12PM में तैनात किया गया है


संभवतः यह विचार एक अनुरोध के संदर्भ को साझा करने के लिए है। यदि हम अलग-अलग रिपॉजिटरी और - डीबीएसईटी कक्षाओं तक पहुंचते हैं और चाहते हैं कि उनके साथ संचालन व्यवहारिक हो जो एक अच्छा समाधान होना चाहिए। खुले स्रोत प्रोजेक्ट mvcforum.com पर एक नजर है। मुझे लगता है कि यूनिट ऑफ वर्क डिजाइन पैटर्न के उनके कार्यान्वयन में किया जाता है।
हुसोमिर वेलचेव

3

मुझे इसके बारे में जो पसंद है वह यह है कि यह इकाई-ऑफ-वर्क को संरेखित करता है (जैसा कि उपयोगकर्ता इसे देखता है - यानी ORM अर्थ में यूनिट-ऑफ-वर्क के साथ।

इसलिए, आप पूरे पृष्ठ को प्रस्तुत करने योग्य बना सकते हैं, जो कि आप नहीं कर सकते थे यदि आप एक नया संदर्भ बनाने के साथ सीआरयूडी विधियों को उजागर कर रहे थे।


2

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

समस्या का कारण यह है कि एक सिंगलटन DbContext एक टाइम बम बन सकता है जो अंततः पूरे डेटाबेस + को .NET ऑब्जेक्ट्स के ओवरहेड को मेमोरी में कैश कर सकता है।

.NoTracking()एक्सटेंशन विधि के साथ केवल Linq प्रश्नों का उपयोग करके इस व्यवहार के आसपास के तरीके हैं । साथ ही इन दिनों पीसी में बहुत सारी रैम होती है। लेकिन आमतौर पर यह वांछित व्यवहार नहीं है।


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

2
कचरा संग्रहकर्ता किसी भी वस्तु को एकत्रित करने के लिए नहीं जा रहा है जो एक सक्रिय स्थैतिक / सिंगलटन ऑब्जेक्ट द्वारा आयोजित किया जाता है। वे ढेर के जीन 2 में समाप्त हो जाएंगे।
दिमित्री एस।

1

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

 public class Foo {
     public string Id {get; set; }
     public string BarId {get; set; }
     // lazy loaded relationship to bar
     public virtual Bar Bar { get; set;}
 }
 var foo = new Foo {
     Id = "foo id"
     BarId = "some existing bar id"
 };
 dbContext.Set<Foo>().Add(foo);
 dbContext.SaveChanges();

 // some other code, using the same context
 var foo = dbContext.Set<Foo>().Find("foo id");
 var barProp = foo.Bar.SomeBarProp; // fails with null reference even though we have BarId set.
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.