इकाई की रूपरेखा। तालिका में सभी पंक्तियों को हटा दें


280

मैं एंटिटी फ्रेमवर्क का उपयोग करके तालिका की सभी पंक्तियों को जल्दी से कैसे निकाल सकता हूं?

मैं वर्तमान में उपयोग कर रहा हूं:

var rows = from o in dataDb.Table
           select o;
foreach (var row in rows)
{
    dataDb.Table.Remove(row);
}
dataDb.SaveChanges();

हालांकि, इसे निष्पादित करने में लंबा समय लगता है।

क्या कोई विकल्प हैं?


22
उत्तरों को पढ़कर मुझे आश्चर्य होता है कि इनमें से कोई भी विज्ञापन TRUNCATEविदेशी प्रमुख बाधाओं की चिंता क्यों नहीं करता ।
गर्ट अर्नोल्ड

2
मैं इस बात से चकित हूँ कि यहाँ कैसे उत्तर दिए गए हैं कि हर कोई Microsoft SQL सर्वर का उपयोग कर रहा है, भले ही Entity फ्रेमवर्क में अन्य डेटाबेस के लिए समर्थन वापस चला जाता है जहाँ तक मुझे जानकारी मिल सकती है और निश्चित रूप से कई वर्षों से इस प्रश्न का पूर्वानुमान लगाता है। । युक्ति: यदि कोई उत्तर वर्ग कोष्ठक (जैसे:) के साथ SQL बयानों में तालिका नामों को उद्धृत [TableName]करता है, तो यह पोर्टेबल नहीं है।
मार्क अमेरी

जवाबों:


293

उन लोगों के लिए जो यह गुगली कर रहे हैं और मेरी तरह यहां समाप्त हो गए हैं, यह है कि वर्तमान में आप इसे EF5 और EF6 में कैसे करते हैं:

context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");

मान लेना संदर्भ एक है System.Data.Entity.DbContext


20
FYI करें, TRUNCATE का उपयोग करने के लिए उपयोगकर्ता के पास तालिका में पूर्व अनुमति होनी चाहिए। ( stackoverflow.com/questions/4735038/… )
एलेक्स

7
@ एलेक्स ने त्रुटि पर एक टन समय बर्बाद कर दिया "ऑब्जेक्ट को माईटेबल नहीं पाया जा सकता क्योंकि यह मौजूद नहीं है या आपके पास अनुमतियाँ नहीं हैं।" उस सटीक कारण के लिए - ALF परमिशन शायद ही कभी EF ऐप्स को दी गई हो, और एरर मैसेज आपको एक जंगली हंस पीछा करता है।
क्रिस मोसचिनी

8
मेरी समस्याएँ तब से थीं जब मेरी तालिका एक विदेशी कुंजी संबंध का हिस्सा थी, भले ही वह उस रिश्ते में पत्ती तालिका थी। मैं संदर्भ का उपयोग करके घाव करता हूं। Database.ExecuteSqlCommand ("DELETE FROM [Interests]"); इसके बजाय
दान Csharpster

2
ध्यान दें कि [यहां से निकलते समय SQL सर्वर के लिए विशिष्ट हैं, TRUNCATEकमांड नहीं है - यह ANSI SQL का हिस्सा है और इसलिए अधिकांश SQL बोलियों (हालांकि SQLite) में काम करेगा।
मार्क अमेरी

207

चेतावनी: निम्नलिखित केवल छोटी तालिकाओं के लिए उपयुक्त है (सोचें <1000 पंक्तियाँ)

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

यह मानता है कि आप परीक्षण या कुछ इसी तरह की स्थिति के लिए ऐसा कर रहे हैं। भी

  • डेटा की मात्रा छोटी है या
  • प्रदर्शन मायने नहीं रखता

बस कॉल करें:

VotingContext.Votes.RemoveRange(VotingContext.Votes);

इस संदर्भ को मानते हुए:

public class VotingContext : DbContext
{
    public DbSet<Vote> Votes{get;set;}
    public DbSet<Poll> Polls{get;set;}
    public DbSet<Voter> Voters{get;set;}
    public DbSet<Candidacy> Candidates{get;set;}
}

Tidier कोड के लिए आप निम्नलिखित एक्सटेंशन विधि की घोषणा कर सकते हैं:

public static class EntityExtensions
{
    public static void Clear<T>(this DbSet<T> dbSet) where T : class
    {
        dbSet.RemoveRange(dbSet);
    }
}

फिर ऊपर बन जाता है:

VotingContext.Votes.Clear();
VotingContext.Voters.Clear();
VotingContext.Candidacy.Clear();
VotingContext.Polls.Clear();
await VotingTestContext.SaveChangesAsync();

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


यह धीमा क्यों हो सकता है?

  1. EF को सभी पंक्तियाँ मिलेंगी (VotingContext.Votes)
  2. और फिर उन्हें हटाने के लिए उनकी आईडी (निश्चित रूप से कैसे, कोई फर्क नहीं पड़ता) का उपयोग करेगा।

यदि आप डेटा की गंभीर मात्रा के साथ काम कर रहे हैं, तो आप SQL सर्वर प्रक्रिया को मार देंगे (यह सभी मेमोरी का उपभोग करेगा) और IIS प्रक्रिया के लिए एक ही बात है क्योंकि EF सभी डेटा को उसी तरह से कैश करेगा जैसे SQL सर्वर। यदि आपकी तालिका में गंभीर मात्रा में डेटा है तो इसका उपयोग न करें।


1
महान जवाब, 10 के एक कारक द्वारा मेरे सभी पंक्तियों के कोड को हटा दें! ध्यान दें कि मुझे ClearDbSet () जैसे कुछ के लिए क्लियर () स्टैटिक एक्सटेंशन मेथड का नाम बदलना पड़ा क्योंकि मेरे पास पहले से ही एक और क्लीयर () स्टैटिक एक्सटेंशन मेथड है जो मेरे प्रोजेक्ट में कहीं और परिभाषित है।
dodgy_coder

1
@dodgy_coder नाम बदलने के लिए आवश्यक नहीं है कि आपने जो कारण दिया है, क्योंकि विस्तार विधि DbSet, IDbSet s और IEnumerable, IList, ICollection, ICache या किसी अन्य के लिए नहीं है जो "Clear" आवश्यक होगा। विस्तार विधि की प्राथमिकता वह प्रकार है जिस पर परिभाषित किया गया है। लेकिन अगर यह आपको और स्पष्ट ध्वनि निरर्थक, महान पढ़ता है! i it, मुझे खुशी है कि यह संपूर्ण ज्ञान में मदद करता है! चीयर्स!
अहमद अलेजो

मुझे खुशी है कि आपने केवल छोटी तालिकाओं के लिए कहा। मुझे आशा है कि लोगों को आपके स्पष्टीकरण का महत्व मिलेगा। चूँकि यह रास्ता सिन्थेटिक शुगर है, इसलिए उचित तरीका वह है जो रॉन सिज़्म ने सुझाया था। क्योंकि आप डेटा को निकालने से पहले लोड नहीं करते हैं। हालांकि ऐसा करने के इस तरीके को दिखाने और समझाने के लिए चीयर्स करते हैं।
yedevtxt 13

3
यह पहचान कुंजी को रीसेट नहीं करता है। इसलिए यदि आप 10 रिकॉर्ड साफ करते हैं, तो अगला अगला अभी भी 11.
एमडीवे

89

SQL की TRUNCATE TABLEकमांड का उपयोग करना सबसे तेज़ होगा क्योंकि यह टेबल पर काम करता है न कि अलग-अलग पंक्तियों पर।

dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]");

मान dataDbलेना एक DbContext(नहीं ObjectContext) है, आप इसे लपेट सकते हैं और इस तरह विधि का उपयोग कर सकते हैं:

var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]");

यदि आप इसे आज़माते हैं, तो आपको एक त्रुटि मिलती है, बसTRUNCATE TABLEDELETE FROM
codeMonkey

1
@codeMonkey बस ध्यान दें कि ये अलग-अलग ऑपरेशन हैं, लेकिन एक ही शुद्ध प्रभाव होगा (लगभग)
रुडी विज़सर

3
लेकिन DELETE IDENTITY बीज को रीसेट नहीं करता है। यह कुछ स्थितियों में समस्याग्रस्त हो सकता है।
स्टीव

43
var all = from c in dataDb.Table select c;
dataDb.Table.RemoveRange(all);
dataDb.SaveChanges();

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

2
@ हेलबनी जब तक यह शायद ही कभी कहा जाता है और इस तरह प्रदर्शन काफी अप्रासंगिक है।
एलेक्स

6
भले ही इसकी शायद ही कभी कहा जाता है यह बुरा है। ईएफ चेंज ट्रैकिंग कितना धीमा है, इसकी वजह से केवल 3000 प्रविष्टियों वाली एक तालिका 30 सेकंड से ऊपर ले जा सकती है।
थोड़ा सा

1
यह केवल छोटे तालिकाओं (<1000 पंक्तियों) के लिए उपयुक्त है
अमीर तूइतौ

मेरे यूनिट टेस्ट में मेरे इन-मेमरी डेटाबेस के लिए परफेक्ट :)
साइमनगेट्स

38
using (var context = new DataDb())
{
     var ctx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext;
     ctx.ExecuteStoreCommand("DELETE FROM [TableName] WHERE Name= {0}", Name);
}

या

using (var context = new DataDb())
{
     context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
}

1
लेकिन जब मैं इसे लिखूंगा। "query.Delete ();" - "हटाएं" को मान्यता नहीं है
जेनिया

1
System.Data.Entity और EntityFrameWork का उर वर्तमान परियोजना में संदर्भ जोड़ें
मनीष मिश्रा

डिलीट करने की कौन सी एक्सटेंशन विधि है?
अहमद अलेजो

जहाँ तक मुझे पता के रूप में वहाँ एक विस्तार तरीका नहीं है Deleteपर IQueryable- मैं मनीष की तरह EntityFramework.Extended कुछ उपयोग कर रहा था अनुमान लगा रहा हूँ: github.com/loresoft/EntityFramework.Extended
अशक्त

मैंने अपना उत्तर संपादित किया है, पहले यह भ्रामक था। @null, आप सही हैं, यह .Deleteएक कस्टम एक्सटेंशन था और पहले उत्तर पोस्ट करने की गर्मी में, इस कस्टम की परिभाषा का उल्लेख करना पूरी तरह से भूल गया .Delete। :)
मनीष मिश्रा

23

आप ऐसा बिना Foreach के कर सकते हैं

dataDB.Table.RemoveRange(dataDB.Table);
dataDB.SaveChanges();

यह सभी पंक्तियों को हटा देगा


क्या यह नेविगेशन प्रॉपर्टी आइटम्स को छोटा कर देगा?
जॉन डियर

19

यह किसी भी sql का उपयोग करने से बचता है

using (var context = new MyDbContext())
{
    var itemsToDelete = context.Set<MyTable>();
    context.MyTables.RemoveRange(itemsToDelete);
    context.SaveChanges();
}

9

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

मैंने public static void Clear<T>(this DbSet<T> dbSet)दृष्टिकोण की कोशिश की है, लेकिन नई पंक्तियाँ नहीं डाली गई हैं। एक और अस्वीकृति यह है कि पूरी प्रक्रिया धीमी है, क्योंकि पंक्तियों को एक-एक करके हटा दिया जाता है।

इसलिए, मैंने TRUNCATEदृष्टिकोण के लिए स्विच किया है, क्योंकि यह बहुत तेज है और यह रोलबैक भी है । यह पहचान को भी हल करता है।

रिपॉजिटरी पैटर्न का उपयोग करके उदाहरण:

public class Repository<T> : IRepository<T> where T : class, new()
{
    private readonly IEfDbContext _context;

    public void BulkInsert(IEnumerable<T> entities)
    {
        _context.BulkInsert(entities);
    }

    public void Truncate()
    {
        _context.Database.ExecuteSqlCommand($"TRUNCATE TABLE {typeof(T).Name}");
    }
 }

 // usage 
 DataAccess.TheRepository.Truncate();
 var toAddBulk = new List<EnvironmentXImportingSystem>();

 // fill toAddBulk from source system
 // ...

 DataAccess.TheRepository.BulkInsert(toAddBulk);
 DataAccess.SaveChanges();

बेशक, जैसा कि पहले ही उल्लेख किया गया है, इस समाधान का उपयोग विदेशी कुंजी (TRUNCATE विफल) द्वारा संदर्भित तालिकाओं द्वारा नहीं किया जा सकता है।


दो टिप्पणियाँ: 1. तालिका का नाम [...] में लपेटा जाना चाहिए। मेरी कक्षाओं में से एक / तालिकाओं को "लेनदेन" कहा जाता है, जो एक SQL कीवर्ड है। 2. यदि लक्ष्य इकाई परीक्षण के लिए एक DB में सभी तालिकाओं को साफ़ करना है, तो विदेशी कुंजी बाधाओं के साथ मुद्दों को आसानी से टेबल को आदेश देने के द्वारा चारों ओर काम किया जा सकता है ताकि बच्चे की तालिकाओं को माता-पिता की तालिकाओं से पहले छोटा किया जा सके।
क्रिस्टोफ़

@Christoph - 1. हाँ, यह सच है। मुझे वह याद आया, क्योंकि मैं हमेशा कीवर्ड से बचने के लिए तालिकाओं का नाम देता हूं क्योंकि इससे परेशानी हो सकती है। 2. अगर मुझे सही से याद है, तो FK द्वारा संदर्भित तालिकाओं को छोटा नहीं किया जा सकता है (SQL Server थ्रो Cannot truncate table because it is being referenced by a FOREIGN KEY constraint), भले ही वे खाली हों, इसलिए FK को गिरा दिया जाना चाहिए औरTRUNCATE वैसे भी उपयोग करने के लिए इसे फिर से बनाया जाना चाहिए ।
एलेक्सी

5

अगर

      using(var db = new MyDbContext())
            {
               await db.Database.ExecuteSqlCommandAsync(@"TRUNCATE TABLE MyTable"););
            }

का कारण बनता है

तालिका 'MyTable' को काट नहीं सकते क्योंकि यह एक FOREIGN कुंजी बाधा द्वारा संदर्भित किया जा रहा है।

मैं इसका उपयोग करता हूं:

      using(var db = new MyDbContext())
               {
                   await db.Database.ExecuteSqlCommandAsync(@"DELETE FROM MyTable WHERE ID != -1");
               }

1
यदि आपके पास विदेशी मुख्य बाधाएँ हैं: (1) SQL को "DELETE FROM MyTable" से सरल बनाया जा सकता है। (2) यदि आपने इसे ऑटोइनक्रैमेंट (ट्रंकैट करता है) पर सेट किया है तो यह आईडी काउंटर को रीसेट नहीं करेगा।
RGH

5
var data = (from n in db.users select n);
db.users.RemoveRange(data);
db.SaveChanges();

4

यदि आप अपना पूरा डेटाबेस खाली करना चाहते हैं।

विदेशी-प्रमुख बाधाओं के कारण यह मायने रखता है कि कौन सी सीक्वेंस को काट दिया जाए। यह इस क्रम को पाटने का एक तरीका है।

    public static void ClearDatabase<T>() where T : DbContext, new()
    {
        using (var context = new T())
        {
            var tableNames = context.Database.SqlQuery<string>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME NOT LIKE '%Migration%'").ToList();
            foreach (var tableName in tableNames)
            {
                foreach (var t in tableNames)
                {
                    try
                    {

                        if (context.Database.ExecuteSqlCommand(string.Format("TRUNCATE TABLE [{0}]", tableName)) == 1)
                            break;

                    }
                    catch (Exception ex)
                    {

                    }
                }
            }

            context.SaveChanges();
        }
    }

उपयोग:

ClearDatabase<ApplicationDbContext>();

इसके बाद अपने DbContext को फिर से स्थापित करना याद रखें।


2

SQLite डेटाबेस पर निम्नलिखित काम करता है (एंटिटी फ्रेमवर्क का उपयोग करके)

ऐसा लगता है कि सभी db तालिकाओं को साफ़ करने का सबसे तेज़ तरीका 'संदर्भ .atabase.ExecuteSqlCommand ("कुछ SQL") का उपयोग कर रहा है, जैसा कि ऊपर दिए गए कुछ टिप्पणियों के रूप में भी है। यहां मैं यह दिखाने जा रहा हूं कि तालिकाओं की 'इंडेक्स' गिनती को भी कैसे रीसेट किया जाए।

            context.Database.ExecuteSqlCommand("delete from TableA");
            context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableA'");//resets the autoindex

            context.Database.ExecuteSqlCommand("delete from TableB");
            context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableB'");//resets the autoindex 

            context.Database.ExecuteSqlCommand("delete from TableC");
            context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableC'");//resets the autoindex 

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

नोट: var संदर्भ = नया YourContext ()


1

यह EF 5 में ठीक से काम करता है:

YourEntityModel myEntities = new YourEntityModel();

var objCtx = ((IObjectContextAdapter)myEntities).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [TableName]");

1

EFCore (संस्करण मैं 3.1 का उपयोग कर रहा हूं) में आप सभी पंक्तियों को हटाने के लिए निम्नलिखित का उपयोग कर सकते हैं -

context.Database.ExecuteSqlRaw("TRUNCATE TABLE [TableName]");

0

सभी रिकॉर्ड हटाएं। "ट्रंकट" जैसे प्राथमिक सूचकांक को रीसेट न करें।

/// <summary>
/// SET - DELETE all record by table - no truncate - return deleted records
/// </summary>
public static int setListDelAllMYTABLE()
{
    // INIT
    int retObj = 0;
    using (MYDBEntities ctx = new MYDBEntities())
    {
        // GET - all record
        var tempAllRecord = ctx.MYTABLE.ToList();
        // RESET
        ctx.MYTABLE.RemoveRange(tempAllRecord);
        // SET - final save
        retObj += ctx.SaveChanges();
    }
    // RET
    return retObj;
}

आप उन्हें हटाने के लिए सभी रिकॉर्ड क्यों निकालेंगे? अत्यंत अकुशल
घोड़ी

क्योंकि प्रदर्शन मेरी प्राथमिकता नहीं थी। यह प्रतिरूपकता पर आधारित है, इसलिए यदि आप कोई शर्त जोड़ना चाहते हैं या इसे हटाने से पहले डेटा की जांच करना चाहते हैं, तो आप कर सकते हैं। EF6 SQL I / O के बारे में सबसे धीमा उपकरण है, इसलिए यदि प्रदर्शन प्राथमिकता थी तो EF6 का उपयोग क्यों किया जाना चाहिए ..
रॉबर्टो मुटी

0

मेरे कोड में मेरे पास वास्तव में डेटाबेस ऑब्जेक्ट तक अच्छी पहुंच नहीं थी, इसलिए आप इसे DbSet पर कर सकते हैं जहां आपको किसी भी प्रकार के sql का उपयोग करने की अनुमति है। यह इस तरह से समाप्त हो जाएगा:

var p = await _db.Persons.FromSql("truncate table Persons;select top 0 * from Persons").ToListAsync();

0

यदि MVC, आप कर सकते हैं:

public async Task<IActionResult> DeleteAll()
{
    var list = await _context.YourClass.ToListAsync();
    _context.YourClass.RemoveRange(list);
    await _context.SaveChangesAsync();
    return RedirectToAction(nameof(Index));
}

0

सुनिश्चित करें कि जब आप माता-पिता को हटाने की कोशिश कर रहे हैं तो सभी बच्चे डिलीट पर कैसकेड करेंगे। या बच्चों के पास अशक्त विदेशी कुंजी है।


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