एंटिटी फ्रेमवर्क 6 ट्रांजैक्शन रोलबैक


82

EF6 के साथ आपके पास एक नया लेन-देन है जिसका उपयोग किया जा सकता है:

using (var context = new PostEntityContainer())
        {
            using (var dbcxtransaction = context.Database.BeginTransaction())
            {
                try
                {
                    PostInformation NewPost = new PostInformation()
                    {
                        PostId = 101,
                        Content = "This is my first Post related to Entity Model",
                        Title = "Transaction in EF 6 beta"
                    };
                    context.Post_Details.Add(NewPost);
                    context.SaveChanges();
                    PostAdditionalInformation PostInformation = new PostAdditionalInformation()
                    {
                        PostId = (101),
                        PostName = "Working With Transaction in Entity Model 6 Beta Version"
                    };

                    context.PostAddtional_Details.Add(PostInformation);
                    context.SaveChanges();

                    dbcxtransaction.Commit();
                }
                catch
                {
                    dbcxtransaction.Rollback();
                }
            }
        }

क्या रोलबैक की ज़रूरत तब होती है जब चीजें बग़ल में होती हैं? मैं उत्सुक हूं क्योंकि प्रतिबद्ध विवरण कहता है: "अंतर्निहित स्टोर लेनदेन को पूरा करता है।"

जबकि रोलबैक विवरण कहता है: "अंतर्निहित स्टोर लेनदेन को वापस करता है।"

यह मुझे उत्सुक बनाता है, क्योंकि यह मुझे दिखता है कि अगर कमिट नहीं कहा जाता है, तो पहले निष्पादित कमांड संग्रहीत नहीं की जाएगी (जो मेरे लिए तर्कसंगत लगता है)। लेकिन अगर ऐसा है, तो रोलबैक फ़ंक्शन को कॉल करने का क्या कारण होगा? EF5 में मैंने TransactionScope का उपयोग किया था जिसमें रोलबैक फ़ंक्शन (केवल एक पूर्ण) नहीं था जो मेरे लिए तर्कसंगत लगता था। MS DTC कारणों के कारण मैं अब TransactionScope का उपयोग नहीं कर सकता, लेकिन मैं ऊपर दिए गए उदाहरण की तरह एक कोशिश पकड़ने का भी उपयोग नहीं कर सकता (यानी, मुझे केवल कमिट की आवश्यकता है)।


1
क्या आपने sql में लेनदेन पर पढ़ा है ? EF कि नकल करने की कोशिश करता है। AFAIK, यदि आप sql में लेन-देन नहीं करते हैं, तो इसे वापस ले लिया जाता है।
गन्र

यह प्रश्न भी देखें ।
गन्र

हाँ, मैं SQL में ही लेनदेन के बारे में जानता हूँ। मैं उत्सुक था कि ईएफ क्या करता है, लेकिन अगर वे इसकी नकल करते हैं, तो यह समझ में आता है। मैं देखूंगा कि क्या मैं इसके आसपास काम कर सकता हूं। धन्यवाद!
कूकीज डॉग

SaveChanges () हमेशा एक लेनदेन में होता है जो अपवाद होने पर वापस ले लिया जाएगा। आपके मामले में मैन्युअल रूप से इसे संभालने की कोशिश करने की आवश्यकता नहीं है (इस विशेष मामले में पहले और SaveChangesकेवल एक बार सभी संस्थाओं को जोड़ना बेहतर होगा )।
पावेल

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

जवाबों:


117

आपको Rollbackमैन्युअल रूप से कॉल करने की आवश्यकता नहीं है क्योंकि आप usingस्टेटमेंट का उपयोग कर रहे हैं ।

DbContextTransaction.Disposeusingब्लॉक के अंत में विधि को बुलाया जाएगा । और यह स्वचालित रूप से लेनदेन को रोलबैक करेगा यदि लेनदेन सफलतापूर्वक प्रतिबद्ध नहीं है (अपवाद नहीं कहा जाता है या सामना नहीं किया गया है)। निम्नलिखित SqlInternalTransaction.Disposeविधि का स्रोत कोड है ( DbContextTransaction.DisposeSqlServer प्रदाता का उपयोग करते समय यह अंततः इसे सौंप देगा):

private void Dispose(bool disposing)
{
    // ...
    if (disposing && this._innerConnection != null)
    {
        this._disposing = true;
        this.Rollback();
    }
}

आप देखते हैं, यह जांचता है कि _innerConnectionक्या अशक्त नहीं है, यदि नहीं, तो लेन-देन रोलबैक करें (यदि प्रतिबद्ध है, तो _innerConnectionअशक्त होगा)। आइए देखें क्या Commitहै:

internal void Commit() 
{
    // Ignore many details here...

    this._innerConnection.ExecuteTransaction(...);

    if (!this.IsZombied && !this._innerConnection.IsYukonOrNewer)
    {
        // Zombie() method will set _innerConnection to null
        this.Zombie();
    }
    else
    {
        this.ZombieParent();
    }

    // Ignore many details here...
}

internal void Zombie()
{
    this.ZombieParent();

    SqlInternalConnection innerConnection = this._innerConnection;

    // Set the _innerConnection to null
    this._innerConnection = null;

    if (innerConnection != null)
    {
        innerConnection.DisconnectTransaction(this);
    }
}

24

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

हालाँकि, जब आप एंटिटी फ्रेमवर्क के दृष्टिकोण से इसके बारे में सोचते हैं, तो आप देख सकते हैं कि सभी उदाहरण लेन-देन को रोलबैक करने के लिए स्पष्ट कॉल का उपयोग क्यों करते हैं। EF के लिए, डेटाबेस प्रदाता मनमाना और प्लग-इन है और प्रदाता को MySQL या किसी अन्य डेटाबेस से बदला जा सकता है, जिसका EF प्रदाता कार्यान्वयन है। इसलिए, EF के दृष्टिकोण से, इस बात की कोई गारंटी नहीं है कि प्रदाता स्वचालित रूप से निपटाए गए लेनदेन को रोलबैक कर देगा, क्योंकि EF को डेटाबेस प्रदाता के कार्यान्वयन के बारे में नहीं पता है।

इसलिए, एक सर्वोत्तम अभ्यास के रूप में, EF दस्तावेज़ीकरण अनुशंसा करता है कि आप स्पष्ट रूप से रोलबैक करें - बस किसी दिन आप प्रदाताओं को एक कार्यान्वयन में बदल देते हैं जो निपटान पर ऑटो-रोलबैक नहीं करता है।

मेरी राय में, कोई भी अच्छा और अच्छा लिखित प्रदाता स्वचालित रूप से निपटान में लेनदेन को रोलबैक कर देगा, इसलिए कोशिश-कैच-रोलबैक के साथ उपयोग ब्लॉक के अंदर सब कुछ लपेटने का अतिरिक्त प्रयास ओवरकिल है।


1
इस अंतर्दृष्टि के लिए धन्यवाद। मैं कोड में काम करता हूं और आप अमूर्त वर्ग DbTransaction's Dispose में समाप्त होते हैं जो SqlTransaction में ओवरराइड होता है जिसे खुद Mouhong Lin द्वारा उल्लिखित SqlInternalTransaction कहते हैं।
शॉनफुमो

4
  1. चूंकि आपने लेन-देन को तुरंत रोकने के लिए 'उपयोग' ब्लॉक लिखा है, इसलिए आपको रोलबैक फ़ंक्शन का स्पष्ट रूप से उल्लेख करने की आवश्यकता नहीं है क्योंकि यह निपटान के समय स्वचालित रूप से वापस ले लिया जाएगा (जब तक कि यह प्रतिबद्ध नहीं था)।
  2. लेकिन अगर आप इसका उपयोग बिना ब्लॉक किए करते हैं, तो उस स्थिति में अपवाद के मामले में लेन-देन को रोलबैक करना आवश्यक है (ठीक कैच ब्लॉक में) और वह भी अधिक मजबूत कोड के लिए अशक्त चेक के साथ। BeginTransaction का कार्य लेनदेन के दायरे के विपरीत है (जो कि सभी कार्यों को सफलतापूर्वक पूरा करने के लिए केवल एक पूर्ण कार्य की आवश्यकता है)। इसके बजाय, यह Sql लेनदेन के कामकाज के समान है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.