मैं इकाई ढांचे में ट्रैक किए गए निकाय को कैसे साफ़ कर सकता हूं


84

मैं कुछ सुधार कोड चला रहा हूं जो संस्थाओं के एक बड़े ढेर पर चलता है, क्योंकि इसकी प्रगति की गति कम हो जाती है, ऐसा इसलिए है क्योंकि संदर्भ में ट्रैक किए गए संस्थाओं की संख्या प्रत्येक पुनरावृत्ति के साथ बढ़ जाती है, इसमें लंबा समय लग सकता है इसलिए मैं अंत में बदलावों को बचा रहा हूं। प्रत्येक पुनरावृत्ति प्रत्येक पुनरावृत्ति स्वतंत्र है और प्रीवियस लोडेड संस्थाओं को नहीं बदलता है।

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

तो सवाल है; क्या db संदर्भ में पहले लोड की गई संस्थाओं को साफ़ करने का कोई तरीका है?


7
आप बस कॉल कर सकते हैं context.Entry(entity).State = EntityState.Detachedऔर यह उस विशेष इकाई को ट्रैक करना बंद कर देगा।
बेन रॉबिन्सन

2
आप सिर्फ एक नया संदर्भ क्यों नहीं देते हैं? जब तक आपको बहुत अनुकूलित कोड की आवश्यकता न हो, वास्तव में कोई बड़ा ओवरहेड नहीं है।
एड्रियन नासुई

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

1
@IsThatSo परिवर्तनों में समय लगता है, मुझे DbPerformance की चिंता नहीं है।
खतरनाकमिक्ली ११'१४ को

क्या आपने वास्तव में प्रदर्शन की अड़चन को ट्रैक किया है या ट्रैक किया है, या केवल यह मान रहे हैं?
49समेट अलकन

जवाबों:


120

आप अपने DbContextया एक एक्सटेंशन विधि में एक विधि जोड़ सकते हैं जो ChangeTracker का उपयोग करके सभी जोड़े गए, संशोधित और हटाए गए निकाय को अलग कर सकता है:

public void DetachAllEntities()
{
    var changedEntriesCopy = this.ChangeTracker.Entries()
        .Where(e => e.State == EntityState.Added ||
                    e.State == EntityState.Modified ||
                    e.State == EntityState.Deleted)
        .ToList();

    foreach (var entry in changedEntriesCopy)
        entry.State = EntityState.Detached;
}

5
। कहां ’के बाद sure ToList’ को कॉल करना सुनिश्चित करें। अन्यथा, यह एक सिस्टम फेंकता है। InvalidOperationException: 'संग्रह संशोधित किया गया था; गणना संचालन निष्पादित नहीं हो सकता है। '
मबेद

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

2
(और यह भी var entityवास्तव में होना चाहिए var entryक्योंकि यह प्रविष्टि वास्तविक इकाई नहीं है)
ओट्सोडा

2
@DavidSherret सोचा कि मामला हो सकता है! मैंने इसे पकड़ा क्योंकि मेरे एक परीक्षण ऐप में, 1000 वस्तुओं के माध्यम से साइकिल चलाना और डिटैच के रूप में चिह्नित करना मौजूदा कोड के साथ लगभग 6000 मिलियन लिया। नए के साथ लगभग 15ms :)
oatsoda

3
क्या आपको e.State == EntityState.Unchanged का उपयोग नहीं करना चाहिए? यद्यपि इकाई अपरिवर्तित है, फिर भी इसे संदर्भ में ट्रैक किया जाता है और यह उन संस्थाओं के सेट का एक हिस्सा है, जिन्हें डिटेक्टेन्जेस के दौरान माना जाता है। जैसे आप नई इकाई जोड़ते हैं (यह राज्य में जोड़ा गया है), SaveChanges को कॉल करें और गयी इकाई में अब स्टेट अपरिवर्तित है (यह UnitOfWork पैटर्न के खिलाफ जाता है, लेकिन op ने पूछा: मैं प्रत्येक पुनरावृत्ति के अंत में परिवर्तन सहेज रहा हूं )।
जहॉ

28

1. संभावना: प्रविष्टि को अलग करें

dbContext.Entry(entity).State = EntityState.Detached;

जब आप प्रविष्टि को अलग करते हैं तो परिवर्तन ट्रैकर इसे ट्रैक करना बंद कर देगा (और बेहतर प्रदर्शन में परिणाम होना चाहिए)

देखें: http://msdn.microsoft.com/de-de/library/system.data.entitystate(v=vs.110).aspx

2. संभावना: अपने स्वयं के Statusक्षेत्र + डिस्कनेक्ट किए गए संदर्भों के साथ काम करें

शायद आप अपनी इकाई की स्थिति को स्वतंत्र रूप से नियंत्रित करना चाहते हैं ताकि आप डिस्कनेक्ट किए गए ग्राफ़ का उपयोग कर सकें। इकाई स्थिति के लिए एक संपत्ति जोड़ें और dbContext.Entry(entity).Stateप्रदर्शन करते समय इस स्थिति को रूपांतरित करें (ऐसा करने के लिए एक भंडार का उपयोग करें)

public class Foo
{
    public EntityStatus EntityStatus { get; set; }
}

public enum EntityStatus
{
    Unmodified,
    Modified,
    Added
}

एक उदाहरण के लिए निम्नलिखित लिंक देखें: https://www.safaribooksonline.com/library/view/programming-entity-framework/9781449331825/ch04s06.html


मुझे लगता है कि एक एक्सटेंशन पद्धति को जोड़ना और चेंजट्रैक में सभी संस्थाओं को चलाना और उन्हें अलग करना चाहिए।
खतरनाकमिक्ली ११'१४ को १३:०२

15

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

_dbContext = new DbContext();


5
यह आपके लक्ष्य के लिए 'सरल लेकिन काम नहीं करता' समाधान है। यह एकमात्र सही है। संदर्भ जितना संभव हो उतना कम जीना चाहिए, प्रति लेनदेन 1 संदर्भ सबसे अच्छा विकल्प है।
येगोर एंड्रोसोव

2
@Pwrigshihanomoronimo के साथ सहमत, संदर्भ UnitOfWork डिजाइन पैटर्न का अनुसरण करता है। जैसा कि मार्टिन फाउलर द्वारा परिभाषित किया गया है:> एक व्यापार लेनदेन से प्रभावित वस्तुओं की एक सूची बनाए रखता है और> परिवर्तन से बाहर लेखन और संक्षिप्तता> समस्याओं के समाधान का समन्वय करता है।
मिशेल

ऐसा लग रहा था कि यह मेरे लिए चाल है। मैं डेटा को सिंक्रोनाइज़ कर रहा हूं, कुछ हज़ारों पंक्तियों के साथ तालिकाओं में लगभग आधा मिलियन लेनदेन (सम्मिलित करें और अपडेट करें)। इसलिए मैं थोड़ी देर (या कई ऑपरेशन) के बाद OutOfMemoryException से जूझता रहा। यह तब हल हुआ जब मैंने एक X DbContext प्रति X संख्या में लूप बनाए जो कि संदर्भ को री-इंस्टेंस करने के लिए एक प्राकृतिक स्थान था। संभवत: यह बेहतर तरीके से जीसी को ट्रिगर करता है, ईएफ में संभावित मेमोरी लीक और लंबे समय तक चलने वाले संचालन के बारे में सोचने के लिए नहीं। धन्यवाद!
मैट मैग्नम

सुनिश्चित नहीं है कि अगर यह निर्भरता इंजेक्शन के साथ काम करता है
सबरीना लेगट

@SabrinaLeggett ऐसा कोई भी काम नहीं करना चाहिए जहाँ से संदर्भ उत्पन्न हुआ हो
Ogglas

4

मैं बस इस मुद्दे में भाग गया, और अंततः ठेठ .NET कोर निर्भरता इंजेक्शन का उपयोग करने वालों के लिए एक बेहतर समाधान पर ठोकर खाई। आप प्रत्येक ऑपरेशन के लिए स्कॉप्ड DbContext का उपयोग कर सकते हैं। वह पुन: सेट DbContext.ChangeTrackerहो जाएगा ताकि SaveChangesAsync()पिछले पुनरावृत्तियों से चेकिंग संस्थाओं को नुकसान न पहुंचे। यहाँ एक उदाहरण ASP.NET कोर नियंत्रक विधि है:

    /// <summary>
    /// An endpoint that processes a batch of records.
    /// </summary>
    /// <param name="provider">The service provider to create scoped DbContexts.
    /// This is injected by DI per the FromServices attribute.</param>
    /// <param name="records">The batch of records.</param>
    public async Task<IActionResult> PostRecords(
        [FromServices] IServiceProvider provider,
        Record[] records)
    {
        // The service scope factory is used to create a scope per iteration
        var serviceScopeFactory =
            provider.GetRequiredService<IServiceScopeFactory>();

        foreach (var record in records)
        {
            // At the end of the using block, scope.Dispose() will be called,
            // release the DbContext so it can be disposed/reset
            using (var scope = serviceScopeFactory.CreateScope())
            {
                var context = scope.ServiceProvider.GetService<MainDbContext>();

                // Query and modify database records as needed

                await context.SaveChangesAsync();
            }
        }

        return Ok();
    }

यह देखते हुए कि ASP.NET Core परियोजनाएं आमतौर पर DbContextPool का उपयोग करती हैं, यह DbContext ऑब्जेक्ट को बनाता / नष्ट नहीं करता है। (यदि आप रुचि रखते हैं, तो DbContextPool वास्तव में कॉल DbContext.ResetState()और करता है DbContext.Resurrect(), लेकिन मैं सीधे आपके कोड से कॉल करने की अनुशंसा नहीं करूंगा, क्योंकि वे संभवतः भविष्य के रिलीज़ में बदल जाएंगे।) https://github.com/aspnet/EntityFrameworkCore-blob/v2 .2.1 / src / EFCore / आंतरिक / DbContextPool.cs # L157


1

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

using Microsoft.EntityFrameworkCore.Internal;

_context.GetDependencies().StateManager.ResetState();

जैसा कि कोड पर टिप्पणी कहती है;

यह एक आंतरिक एपीआई है जो एंटिटी फ्रेमवर्क कोर बुनियादी ढांचे का समर्थन करता है और सार्वजनिक एपीआई के समान संगतता मानकों के अधीन नहीं है। इसे किसी भी रिलीज में बिना किसी नोटिस के बदला या हटाया जा सकता है। आपको अत्यधिक सावधानी के साथ अपने कोड में सीधे इसका उपयोग करना चाहिए और यह जानते हुए कि ऐसा करने से नए एंटिटी फ्रेमवर्क कोर रिलीज के लिए आवेदन विफल हो सकता है।



-2

वैसे मेरी राय है कि, मेरे अनुभव में, ईएफ, या किसी भी ओआरएम होने के नाते, बहुत अधिक दबाव या जटिल मॉडल के तहत अच्छी तरह से काम नहीं करता है।

यदि आप ट्रैक नहीं करना चाहते हैं, तो वास्तव में मैं कहूंगा कि ऑरम भी क्यों?

यदि गति मुख्य बल है, तो कुछ भी संग्रहीत प्रक्रियाओं और अच्छी अनुक्रमण को नहीं धड़कता है।

और इससे भी आगे, यदि आपके प्रश्न हमेशा आईडी के अनुसार हो तो एक nosql या शायद मुख्य और json के साथ sql का उपयोग करें। यह कक्षाओं और तालिकाओं के बीच प्रतिबाधा की समस्या से बचता है।

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

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