development

엔터티 프레임 워크.

big-blog 2020. 4. 1. 08:01
반응형

엔터티 프레임 워크. 테이블에서 모든 행 삭제


Entity Framework를 사용하여 테이블의 모든 행을 빠르게 제거하는 방법은 무엇입니까?

나는 현재 다음을 사용하고 있습니다 :

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

그러나 실행하는 데 시간이 오래 걸립니다.

대안이 있습니까?


인터넷 검색을하고 나와 같은 결과를 얻은 사람들에게는 현재 EF5 및 EF6에서 수행하는 방법입니다.

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

컨텍스트가 System.Data.Entity.DbContext


경고 : 다음은 작은 테이블에만 적합합니다 (<1000 행).

다음은 SQL이 아닌 엔터티 프레임 워크를 사용하여 행을 삭제하는 솔루션이므로 SQL 엔진 (R / DBM)과 관련이 없습니다.

이것은 테스트 또는 이와 유사한 상황을 위해이 작업을 수행한다고 가정합니다. 어느 한 쪽

  • 데이터 양이 적 거나
  • 성능은 중요하지 않습니다

간단히 전화하십시오 :

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;}
}

단정 한 코드의 경우 다음 확장 방법을 선언 할 수 있습니다.

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();

최근 에이 접근법을 사용하여 각 테스트 케이스 실행마다 테스트 데이터베이스를 정리했습니다 (생성 된 삭제 명령의 형태를 확인하지는 않았지만 매번 DB를 처음부터 다시 작성하는 것보다 빠릅니다).


왜 느려질 수 있습니까?

  1. EF는 모든 행을 가져옵니다 (VotingContext.Votes)
  2. 그런 다음 ID를 사용하여 (정확한 방법은 중요하지 않음) ID를 삭제합니다.

따라서 많은 양의 데이터로 작업하는 경우 EF가 SQL Server와 동일한 방식으로 모든 데이터를 캐시하므로 IIS 서버에 대해 SQL 서버 프로세스 (모든 메모리를 소비 함)를 중지시킵니다. 테이블에 많은 양의 데이터가 포함되어 있으면 이것을 사용하지 마십시오.


SQL TRUNCATE TABLE명령은 개별 행이 아닌 테이블에서 작동 할 때 가장 빠릅니다.

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

dataDbDbContext(가 아닌 ObjectContext) 것으로 가정하면 랩핑하여 다음과 같은 방법을 사용할 수 있습니다.

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

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

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]");
}

이것은 SQL 사용을 피합니다.

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

Foreach없이 할 수 있습니다

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

이것은 모든 행을 제거합니다


"리프"테이블의 내용을 완전히 업데이트하는 (FK가 가리 키지 않는) 특정 사례를 처리해야 할 때이 질문에 부딪 쳤습니다. 이것은 모든 행을 제거하고 새로운 행 정보를 넣는 것과 관련이 있으며 트랜잭션으로 수행해야합니다 (삽입이 어떤 이유로 든 실패하면 빈 테이블로 끝나고 싶지 않습니다).

public static void Clear<T>(this DbSet<T> dbSet)접근 방식 을 시도 했지만 새 행이 삽입되지 않았습니다. 또 다른 단점은 행이 하나씩 삭제되므로 전체 프로세스가 느리다는 것입니다.

그래서 TRUNCATE훨씬 빠르며 롤백 가능 하기 때문에 접근 방식으로 전환했습니다 . 또한 ID를 재설정합니다.

리포지토리 패턴을 사용하는 예 :

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 실패).


만약

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

원인

테이블 'MyTable'이 FOREIGN KEY 제약 조건에 의해 참조되고 있으므로 잘라낼 수 없습니다.

나는 이것을 사용한다 :

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

전체 데이터베이스를 지우려면

외래 키 제약 조건으로 인해 테이블이 잘리는 순서가 중요합니다. 이것이이 순서를 무차별시키는 방법입니다.

    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를 다시 인스턴스화해야합니다.


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

이것은 EF 5에서 제대로 작동합니다 :

YourEntityModel myEntities = new YourEntityModel();

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

모든 레코드를 삭제하십시오. "잘라 내기"와 같은 기본 색인을 재설정하지 마십시오.

/// <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;
}

내 코드에서는 실제로 데이터베이스 개체에 대한 좋은 액세스 권한이 없으므로 DbSet에서 수행 할 수 있으며 모든 종류의 SQL을 사용할 수 있습니다. 다음과 같이 끝납니다.

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

참고 URL : https://stackoverflow.com/questions/15220411/entity-framework-delete-all-rows-in-table

반응형