【问题标题】:How should I remove all elements in a DbSet?我应该如何删除 DbSet 中的所有元素?
【发布时间】:2012-05-04 12:17:29
【问题描述】:

使用 Entity Framework 4.3 删除 System.Data.Entity.DbSet 中所有元素的最佳方法是什么?

【问题讨论】:

    标签: c# .net entity-framework-4


    【解决方案1】:
    dbContext.Database.ExecuteSqlCommand("delete from MyTable");
    

    (不开玩笑。)

    问题在于 EF 不支持任何批处理命令,并且不使用直接 DML 删除集合中所有实体的唯一方法是:

    foreach (var entity in dbContext.MyEntities)
        dbContext.MyEntities.Remove(entity);
    dbContext.SaveChanges();
    

    或者为了避免加载完整的实体,可能会便宜一点:

    foreach (var id in dbContext.MyEntities.Select(e => e.Id))
    {
        var entity = new MyEntity { Id = id };
        dbContext.MyEntities.Attach(entity);
        dbContext.MyEntities.Remove(entity);
    }
    dbContext.SaveChanges();
    

    但在这两种情况下,您都必须加载 所有 实体或 所有 关键属性,然后从集合中一个一个地删除实体。此外,当您调用SaveChanges 时,EF 将向数据库发送 n(= 集合中的实体数)DELETE 语句,这些语句也会在数据库中一一执行(在单个事务中)。

    因此,直接 SQL 显然更适合此目的,因为您只需要一个 DELETE 语句。

    【讨论】:

    • dbContext.Database.ExecuteSqlCommand之后需要打电话给SaveChanges吗?
    • 真正的问题是 DbContext 如何提供对其所有 DbSets/Entities 的访问?除非您使用反射,否则无法循环它们。这是您在提到“MyEntities”时所想到的吗?
    • RemoveRange 代替 Remove 怎么样?你会说,"that was only introduced in EF 6 and OP asked about EF 4.*"?
    【解决方案2】:

    旧帖,但现在有一个 RemoveRange 方法:

        dbContext.MyEntities.RemoveRange(dbContext.MyEntities);
        dbContext.SaveChanges();
    

    【讨论】:

    • 我使用这个答案是因为代码简单明了。我确信有更有效的方法可以做到这一点,但我正在使用一个将在一夜之间运行的 Azure WebJob,所以目前这不是问题。
    • RemoveRange 的问题在于,您仍然必须从数据库中查询所有实体(或至少查询 ID),因为此方法只是 foreach 的包装器。
    • 请添加文档链接!
    【解决方案3】:

    这是您可以在代码中执行此操作的另一种方式。

    public static class Extensions
    {
        public static void DeleteAll<T>(this DbContext context)
            where T : class
        {
            foreach (var p in context.Set<T>())
            {
                context.Entry(p).State = EntityState.Deleted;
            }
        }
    }
    

    真正调用方法并清除集合:

    myDbContext.DeleteAll<MyPocoClassName>();
    

    【讨论】:

      【解决方案4】:

      如果您想删除所有元素不编写任何 SQL 并且只执行 Single Db Call

      Entity Framework Extended Library 提供批量删除方法。

      context.Users.Delete();
      

      【讨论】:

      • 之后你还需要调用context.SaveChanges()吗?...如果不是,我假设扩展库的Delete() 方法发生在与已发生的任何其他数据库更改不同的事务中自从上次拨打context.SaveChanges() 以来?
      【解决方案5】:

      由于接受的答案仅提及以下方法:

      context.Database.ExecuteSqlCommand("delete from MyTable");
      

      而不是提供替代方案,我设法编写了一个方法,您可以使用它来避免加载所有实体,然后循环它们并改用 ExecuteSqlCommand

      假设使用工作单元,其中上下文为 DbContext:

      using System.Data.Entity.Core.Objects;
      using System.Text.RegularExpressions;
      
      public void DeleteAll()
      {
          ObjectContext objectContext = ( (IObjectContextAdapter)context ).ObjectContext;
          string sql = objectContext.CreateObjectSet<T>().ToTraceString();
          Regex regex = new Regex( "FROM (?<table>.*) AS" );
          Match match = regex.Match( sql );
          string tableName = match.Groups[ "table" ].Value;
      
          context.Database.ExecuteSqlCommand( string.Format( "delete from {0}", tableName ) );
      }
      

      第一个代码块检索 ExecuteSqlCommand 方法中所需的表名。

      用法:

      using ( var context = new UnitOfWork() )
      {
          context.MyRepository.DeleteAll();
      }
      

      不需要打电话

      context.SaveChanges()
      

      【讨论】:

        【解决方案6】:

        如果您正在使用工作单元和通用存储库,您可能会发现以下有用

        public virtual void DeleteWhere(Expression<Func<TEntity, bool>> filter = null,
                    Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
                    string includeProperties = "")
                {
                    IQueryable<TEntity> query = dbSet;
                    if (filter != null)
                    {
                        query = query.Where(filter);
                    }
                    foreach (var includeProperty in includeProperties.Split
                        (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        query = query.Include(includeProperty);
                    }
        
                    foreach (var entity in query)
                    {
                        context.Entry(entity).State = EntityState.Deleted;
                    }
                }
        

        用法:

        uow.myRepositoryName.DeleteWhere(u => u.RoomId == roomId);
        uow.Save();
        

        【讨论】:

          【解决方案7】:

          使用存储库模式,您可以在其中为存储库指定模型的类型,它可以适用于任何模型类型。

              public async Task<int> RemoveAllAsync()
              {
                  Context.Set<T>().RemoveRange(await Context.Set<T>().ToListAsync());
                  return await Context.SaveChangesAsync();
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-04-06
            • 2011-06-20
            • 2011-04-28
            • 1970-01-01
            • 2013-10-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多