source

엔티티 프레임워크의 모든 엔티티 삭제

ittop 2023. 4. 27. 22:43
반응형

엔티티 프레임워크의 모든 엔티티 삭제

Entity Framework 4+를 사용하여 모든 테이블(모든 엔터티)의 내용을 삭제하려고 합니다.이것이 어떻게 행해지는가?

이렇게 하면 기본 데이터베이스가 MSSQL이라고 가정할 때 개별 엔터티 개체를 삭제하는 것보다 훨씬 더 효과적으로 수행됩니다.

foreach (var tableName in listOfTableNames)
{
    context.ExecuteStoreCommand("TRUNCATE TABLE [" + tableName + "]");
}

물론 테이블에 외래 키 관계가 있는 경우 외래 키 테이블을 삭제하기 전에 외래 키 테이블을 삭제할 수 있도록 테이블 이름 목록을 적절한 순서로 설정해야 합니다.

게으른 사람들을 위해, 답을 찾을 때 내가 직접 떠올린 코드:

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)
        {
            context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableName));
        }

        context.SaveChanges();
    }
}

간단한 설명:권한 부족으로 인해 테이블을 자르지는 않습니다. 문제가 되지 않는다면 언제든지 잘라내십시오.__Migration 테이블where 문에서 기록을 무시합니다.

업데이트: 몇 가지 조사를 통해 더 나은 솔루션을 찾았습니다(별로 좋지는 않지만 필요한 열만 삭제).

public static void ClearDatabase(DbContext context)
{
    var objectContext = ((IObjectContextAdapter)context).ObjectContext;
    var entities = objectContext.MetadataWorkspace.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace).BaseEntitySets;
    var method = objectContext.GetType().GetMethods().First(x => x.Name == "CreateObjectSet");
    var objectSets = entities.Select(x => method.MakeGenericMethod(Type.GetType(x.ElementType.FullName))).Select(x => x.Invoke(objectContext, null));
    var tableNames = objectSets.Select(objectSet => (objectSet.GetType().GetProperty("EntitySet").GetValue(objectSet, null) as EntitySet).Name).ToList();

    foreach (var tableName in tableNames)
    {
        context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableName));
    }

    context.SaveChanges();
}

EF 6의 경우:

DbSet<Entity>.RemoveRange(DbSet<Entity>);

다음과 같은 코드를 사용하여 표를 반복합니다.

context.GetType().GetProperties()
.Where(propertyInfo => propertyInfo.PropertyType == typeof(Table<>))
.Select(propertyInfo => propertyInfo.GetValue(context, null) as ITable).ToList()
.Foreach(table =>
{
    //code that deletes the actual tables records.
}
);

저는 @Wojciech Markowski의 훌륭한 답변을 개선하기 위해 노력하고 싶습니다.

나처럼 게으르고 외래 키 제약 조건을 확인하고 싶지 않다면 다음 방법을 사용할 수 있습니다.

        private void ClearDatabase(TContext context)
    {
            // disable all foreign keys
            //context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable @command1 = 'ALTER TABLE ? NOCHECK CONSTRAINT all'");

            List<string> tableNames = context.Database.SqlQuery<string>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME NOT LIKE '%Migration%'").ToList();

            for (int i = 0; tableNames.Count>0; i++)
            {
                try
                {
                    context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableNames.ElementAt(i % tableNames.Count)));
                    tableNames.RemoveAt(i % tableNames.Count);
                    i = 0;
                }
                catch { } // ignore errors as these are expected due to linked foreign key data             
            }


            context.SaveChanges();
    }

ClearDatabase 메서드는 테이블 목록을 검토한 후 정리합니다. FK 제약 조건이 발견되면 예외를 적용하고 다음 테이블로 이동합니다.마지막에 모든 테이블이 삭제됩니다.

또한 모든 FK 제약 조건을 해제하는 것이 괜찮다면 라인을 사용하여 모든 제약 조건을 비활성화할 수 있습니다.

context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable @command1 = 'ALTER TABLE ? NOCHECK CONSTRAINT all'");

한 가지 더:삭제하지 않고 모든 테이블을 삭제하려면 다음 행을 바꿉니다.

context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableNames.ElementAt(i % tableNames.Count)));

포함:

context.Database.ExecuteSqlCommand(string.Format("DROP TABLE {0}", tableNames.ElementAt(i % tableNames.Count)));

코드 우선 마이그레이션으로 엔티티 프레임워크 6에서 이 답변을 직접 확인했습니다.

편집: 더 나은 버전:

        private void ClearDatabase(MrSaleDbContext context)
    {
        //Optional: disable all foreign keys (db-schema will be loosed).
        //context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable @command1 = 'ALTER TABLE ? NOCHECK CONSTRAINT all'");

        List<string> tableNames = context.Database.SqlQuery<string>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME NOT LIKE '%Migration%' AND TABLE_NAME NOT LIKE 'AspNet%'").ToList();

        for (int i = 0; tableNames.Count > 0; i++)
        {
            try
            {
                //To delete all tables and not just clean them from data, replace "DELETE FROM {0}" in "DROP TABLE {0}":
                context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableNames.ElementAt(i % tableNames.Count)));
                tableNames.RemoveAt(i % tableNames.Count);
                i = -1; //flag: a table was removed. in the next iteration i++ will be the 0 index.
            }
            catch (System.Data.SqlClient.SqlException e)   // ignore errors as these are expected due to linked foreign key data    
            {                    
                if ((i % tableNames.Count) == (tableNames.Count - 1))
                {
                    //end of tables-list without any success to delete any table, then exit with exception:
                    throw new System.Data.DataException("Unable to clear all relevant tables in database (foriegn key constraint ?). See inner-exception for more details.", e);
                }

            }

        }

catch 블록의 if 문은 테이블을 삭제하지 않고 테이블 목록의 마지막 인덱스에 도달했는지 확인합니다.이 경우 무한 루프 대신 예외를 던지고 를 종료합니다.

(In.NetCore) 테이블에서 RemoveRange를 사용하고 테이블 자체를 Parameter(파라미터)로 지정할 수 있습니다.

Tablename.RemoveRange(Tablename);

외부 키 내에서 잘라낼 수 없습니다.

그런 다음 DbContext에 대한 확장 방법을 만들었습니다.

사용법은 간단합니다.

db.cruncates(); // 모든 테이블을 삭제합니다.

db.cruncates("Test1", "Test2"); // "Test1, Test2" 테이블만 삭제

public static class DbContextExtension
{
    public static int Truncates(this DbContext db, params string[] tables)
    {
        List<string> target = new List<string>();
        int result = 0;

        if (tables == null || tables.Length == 0)
        {
            target = db.GetTableList();
        }
        else
        {
            target.AddRange(tables);
        }

        using (TransactionScope scope = new TransactionScope())
        {
            foreach (var table in target)
            {
                result += db.Database.ExecuteSqlCommand(string.Format("DELETE FROM  [{0}]", table));
                db.Database.ExecuteSqlCommand(string.Format("DBCC CHECKIDENT ([{0}], RESEED, 0)", table));
            }
            
            scope.Complete();
        }

        return result;
    }

    public static List<string> GetTableList(this DbContext db)
    {
        var type = db.GetType();

        return db.GetType().GetProperties()
            .Where(x => x.PropertyType.Name == "DbSet`1")
            .Select(x => x.Name).ToList();
    }
}

이건 내게 효과가 있어요...EF v3.1.5

context.ModelName.RemoveRange(context.ModelName.ToList());
context.SaveChanges();

저는 제 몫을 기부하고 싶습니다.

저는 이 질문을 생각해 냈습니다. 이 질문은 저자가 요청한 것과 정확히 일치합니다.이것은.NET 5.

var query = "sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL; SET QUOTED_IDENTIFIER ON; DELETE FROM ?; ALTER TABLE ? CHECK CONSTRAINT ALL;'"
context.Database.ExecuteSqlRaw(query);

언급URL : https://stackoverflow.com/questions/6089403/delete-all-entities-in-entity-framework

반응형