엔티티 프레임워크테이블의 모든 행 삭제
엔티티 프레임워크를 사용하여 테이블의 모든 행을 빠르게 삭제하려면 어떻게 해야 합니까?
현재 사용하고 있는 것:
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
편집:
현재 net6.0(dotnet 6 core)에서는 다음 작업을 수행할 수 있습니다.
context.Database.ExecuteSqlRaw("TRUNCATE TABLE [TableName]");
또는 비동기 오버로드를 사용합니다.
await context.Database.ExecuteSqlRawAsync("TRUNCATE TABLE [TableName]");
이란 '하다'에서 확장법입니다.Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions
MySql에서)해야 할 수 the Doing the ( MySql ) 。SET FOREIGN_KEY_CHECKS = 0;
가 없는 것 )
context.Database.ExecuteSqlRaw("SET FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE [TableName];");
따라서 전체 데이터베이스를 잘라내려는 경우(경우에 따라서는 중단되지 않음) 다음을 수행할 수 있습니다.
var tableNames = context.Model.GetEntityTypes()
.Select(t => t.GetTableName())
.Distinct()
.ToList();
foreach (var tableName in tableNames)
{
context.Database.ExecuteSqlRaw($"SET FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE `{tableName}`;");
}
경고:다음 항목은 작은 테이블에만 적합합니다(1000줄 미만).
다음은 SQL이 아닌 엔티티 프레임워크를 사용하여 행을 삭제하는 솔루션이며 SQL Engine(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;}
}
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();
최근 이 방법을 사용하여 각 테스트 케이스 실행 시 테스트 데이터베이스를 정리했습니다(생성된 삭제 명령어 형식을 확인하지 않았지만 매번 처음부터 DB를 다시 작성하는 것보다 확실히 빠릅니다).
왜 이렇게 느려?
- EF는 모든 행을 가져옵니다(Voting Context).투표)
- 그런 다음 ID를 사용하여 삭제합니다(정확한 방법은 알 수 없지만 상관 없음).
따라서 대량의 데이터를 사용하는 경우 SQL Server 프로세스가 중단되고(메모리가 모두 소비됨), EF는 SQL Server와 동일한 방식으로 모든 데이터를 캐시하기 때문에 IIS 프로세스도 중단됩니다.테이블에 심각한 양의 데이터가 포함되어 있는 경우에는 이 항목을 사용하지 마십시오.
SQL 명령어는 개별 행이 아닌 테이블에서 작동하므로 가장 빠르게 사용할 수 있습니다.
dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
정 dataDb
는 입니다.DbContext
(아니오)가 .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]");
}
Foreach 없이도 할 수 있어
dataDB.Table.RemoveRange(dataDB.Table);
dataDB.SaveChanges();
그러면 모든 행이 제거됩니다.
이렇게 하면 SQL을 사용하지 않아도 됩니다.
using (var context = new MyDbContext())
{
var itemsToDelete = context.Set<MyTable>();
context.MyTables.RemoveRange(itemsToDelete);
context.SaveChanges();
}
context.TableName.RemoveRange(context.TableName);
context.SaveChanges();
EF Core 7.0은 일괄 업데이트 및 삭제 시멘틱을 추가하여 이 문제를 완전히 해결합니다.
await dataDB.Table.ExecuteDeleteAsync();
이 구문은 즉시 기본(SQL) 명령을 실행하여 테이블에서 데이터를 삭제합니다.엔티티 추적, 삭제 마킹 및 대기에는 문제가 없습니다.UpdateDatabase
데이터베이스에 대해 트랜잭션을 실행합니다.
, 복수의 「」, 「」가 있는 해 주세요.ExecuteDelete
★★★★★★★★★★★★★★★★★」ExecuteUpdate
명령어는 기본적으로 단일 트랜잭션에 포함되지 않습니다.그러나 DbContext 트랜잭션 API는 트랜잭션에서 이러한 명령을 줄바꿈하는 일반적인 방법으로 사용할 수 있습니다.
특정 사례를 다루어야 할 때 이 질문을 하게 되었습니다. "리프" 테이블에서 콘텐츠를 완전히 업데이트(FK가 이를 가리키지 않음).여기에는 모든 행을 삭제하고 새 행 정보를 넣는 작업이 포함되며 트랜잭션 방식으로 수행해야 합니다(어떤 이유로든 삽입이 실패하더라도 빈 테이블로 끝나는 것은 원치 않습니다).
가 먹어봤는데요.public static void Clear<T>(this DbSet<T> dbSet)
이치노또 다른 단점은 행이 하나씩 삭제되기 때문에 전체 프로세스가 느리다는 것입니다.
so래는으로 .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 실패).
한다면
using(var db = new MyDbContext())
{
await db.Database.ExecuteSqlCommandAsync(@"TRUNCATE TABLE MyTable"););
}
원인들
'MyTable' 테이블은 FORENAL KEY 제약 조건이 참조하고 있으므로 잘라낼 수 없습니다.
나는 이것을 사용한다.
using(var db = new MyDbContext())
{
await db.Database.ExecuteSqlCommandAsync(@"DELETE FROM MyTable WHERE ID != -1");
}
var data = (from n in db.users select n);
db.users.RemoveRange(data);
db.SaveChanges();
다음은 SQLite 데이터베이스(Entity Framework 사용)에서 작동합니다.
은 DB를 사용하는 것 .context.Database.ExecuteSqlCommand("some 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 context = new YourContext()
데이터베이스 전체를 클리어하는 경우.
외부 키 제약으로 인해 테이블이 잘리는 시퀀스가 중요합니다.이것은 이 시퀀스를 강제하는 방법입니다.
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를 다시 설치해야 합니다.
EFCore(사용하고 있는 버전은 3.1)에서는 다음 명령을 사용하여 모든 행을 삭제할 수 있습니다.
context.Database.ExecuteSqlRaw("TRUNCATE TABLE [TableName]");
난 이거면 되는데...EF v3.1.5
context.ModelName.RemoveRange(context.ModelName.ToList());
context.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;
}
MVC의 경우 다음 작업을 수행할 수 있습니다.
public async Task<IActionResult> DeleteAll()
{
var list = await _context.YourClass.ToListAsync();
_context.YourClass.RemoveRange(list);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
부모를 삭제하려고 할 때 삭제 시 모든 자녀가 계단식으로 이동해야 합니다.또는 아이들은 null 가능한 외부 키를 가지고 있다.
다음은 Ron이 자주 사용하는 솔루션의 변형입니다.이러한 솔루션은 엔티티 프레임워크 클래스의 기본 테이블 이름을 결정하기 위해 스택 오버플로우에서 다른 일반적인 솔루션을 이용하여 하드코드된 문자열 테이블 이름을 사용하지 않도록 합니다.
이러한 확장 방법을 사용하면 솔루션은 다음과 같습니다.
_dbContext.TruncateTable<TheTableName>();
(사용)this.TruncateTable<...
EF DBContext 클래스 또는 부분 클래스 파일 내에서 코드를 편집하는 경우)
확장 클래스는 다음과 같습니다.
public static class EntityFrameworkExtensions
{
private static string ParseTableNameFromSQL(string sql)
{
Regex regex = new Regex("FROM (?<table>.*) AS");
Match match = regex.Match(sql);
string table = match.Groups["table"].Value;
return table;
}
public static string GetTableName<T>(this IObjectContextAdapter context) where T : class =>
ParseTableNameFromSQL(context.ObjectContext.CreateObjectSet<T>().ToTraceString());
public static void TruncateTable<T>(this DbContext dbContext) where T : class =>
dbContext.Database.ExecuteSqlCommand($"TRUNCATE TABLE {dbContext.GetTableName<T>()}");
public static void DeleteAllTableRows<T>(this DbContext dbContext) where T : class =>
dbContext.Database.ExecuteSqlCommand($"DELETE FROM {dbContext.GetTableName<T>()}");
}
마지막 확장 방식DeleteAllTableRows
테이블이 잘릴 수 없는 경우(예를 들어 외부 키 참조로 인해) 유용한 대체 수단입니다.이 방법은 엔티티 프레임워크보다 훨씬 빠릅니다.RemoveAll
대안.
EF Core 3에 대응
public static class EntityExtensions
{
public static async Task ClearAsync<T>(this DbSet<T> dbSet) where T : class
{
var command = dbSet.CreateDbCommand();
command.CommandText = $"TRUNCATE TABLE {dbSet.EntityType.GetSchema()}.{dbSet.EntityType.GetTableName()}";
await command.ExecuteNonQueryAsync();
}
}
단, dbSet에 주의해 주세요.CreateDbCommand는 확장입니다.
나의 해결책, 내 아이디어를 혼합하고, 몇 가지 답을 (이 스레드에서 하나, 그리고 이것과 이것 또한 성찰하기 위해) 그리고 몇 가지 다른 조건들을 다루려고 한다.
EF6 기반이지만 다음과 같은 확장 기능만 수정하면 됩니다.GetTableName<TEntity>
.
솔루션:
- 확장자를 사용하기 때문에 필요한 것은
DbSet
발사하다 - 행 카운트 임계값이 설정되어 있습니다.
RemoveRange
또는 SQL 실행을 통해 성능 문제를 방지합니다. - SQL 버전은 다음을 기반으로 합니다.
DELETE
대신TRUNCATE
외부 키 문제를 피하기 위해 (물론 고객의 요건에 적합해야 합니다) - 에는 변경을 인라인으로 저장하기 위한 파라미터가 있습니다.
private const int RangeLimit = 100;
private static void ClearTable<TEntity>(this DbSet<TEntity> dataSet, bool saveChanges = true) where TEntity : class
{
DbContext context = null;
if (dataSet.Count() > RangeLimit)
{
context = dataSet.GetContext();
context.Database.ExecuteSqlCommand($"DELETE FROM [{context.GetTableName<TEntity>()}]");
}
else
{
dataSet.RemoveRange(dataSet);
}
if (!saveChanges)
{
return;
}
if (context == null)
{
context = dataSet.GetContext();
}
context.SaveChanges();
}
private static DbContext GetContext<TEntity>(this DbSet<TEntity> dbSet)
where TEntity : class
{
var internalSet = dbSet
.GetType()
.GetField("_internalSet", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(dbSet);
var internalContext = internalSet?.GetType().BaseType
?.GetField("_internalContext", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(internalSet);
return (DbContext)internalContext?.GetType()
.GetProperty("Owner", BindingFlags.Instance | BindingFlags.Public)
?.GetValue(internalContext, null);
}
public static string GetTableName<TEntity>(this DbContext context) where TEntity : class
{
return (context as IObjectContextAdapter).ObjectContext.CreateObjectSet<TEntity>().EntitySet.Name;
}
이름 있는 데이터베이스 테이블을 사용하여 수행할 작업만 있으면 됩니다.Entries
는 다음과 같습니다.
databaseContext.Entries.ClearTable();
변경 내용을 저장하거나 저장하지 않을 경우:
databaseContext.Entries.ClearTable(false);
코드의 심플화를 위해서, 반사에 근거하고 있습니다.물론 성능 트레이드오프가 있지만, 각 테이블마다 한 번씩 반영되기 때문에 이러한 조건에서는 완전히 수용할 수 있어야 합니다.
그것은 매우 깨끗한 해결책이다.
_context.RemoveRange(_context.ModelName);
_context.SaveChanges();
여기에서는, 거의 모든 답변에 관한 몇개의 문제가 있습니다.
.1] SQL.모든 데이터베이스 엔진에서 브래킷이 작동합니까?
프레임워크 2) 엔티티 Remove
★★★★★★★★★★★★★★★★★」RemoveRange
호출합니다. 그러면 조작의 영향을 받는 모든 엔티티가 메모리에 로드됩니다.
3 ] 3 3 3 3 3 3 3 3 3 3 3 3 。외부 키 참조와 단절되어 일부 데이터베이스 엔진에서 작동하지 않을 수 있습니다.
https://entityframework-plus.net/,을 사용하면 데이터베이스 플랫폼 간 작업을 처리하고 삭제를 올바른 sql문으로 변환하여 엔티티를 메모리에 로드하지 않습니다.라이브러리는 자유롭고 오픈 소스입니다.
면책사항:저는 nuget 패키지에 소속되어 있지 않습니다.그들은 훨씬 더 많은 것을 할 수 있는 유료 버전을 제공한다.
언급URL : https://stackoverflow.com/questions/15220411/entity-framework-delete-all-rows-in-table
'programing' 카테고리의 다른 글
ASP.Net 웹 응용 프로그램 추가 구성 변환이 회색으로 표시됨 (0) | 2023.04.23 |
---|---|
메서드 이름과 행 번호를 출력하여 NSLog를 조건부로 비활성화하려면 어떻게 해야 합니까? (0) | 2023.04.18 |
List View를 만듭니다.ScrollIntoView 항목을 ListView 중앙으로 스크롤합니다(C#). (0) | 2023.04.18 |
Windows 배치 파일에서 팝업/메시지 상자 표시 (0) | 2023.04.18 |
div 내부의 이미지에 이미지 아래에 여분의 공간이 있습니다. (0) | 2023.04.18 |