我正在使用实体框架从表中删除几个项目。没有外键/父对象,所以我不能用OnDeleteCascade处理这个。

现在我正在做这个:

var widgets = context.Widgets
    .Where(w => w.WidgetId == widgetId);

foreach (Widget widget in widgets)
{
    context.Widgets.DeleteObject(widget);
}
context.SaveChanges();

它工作,但foreach困扰我。我使用EF4,但我不想执行SQL。我只是想确保我没有错过任何东西-这是最好的,对吧?我可以用扩展方法或helper来抽象它,但在某些地方我们还是要用foreach,对吧?


当前回答

UUHHIVS是一种非常优雅和快速的批量删除方法,但必须小心使用:

自动生成事务:它的查询将包含在事务中 数据库上下文独立性:它的执行与上下文无关。

这些问题可以通过控制事务来避免。下面的代码演示了如何以事务的方式批量删除和批量插入:

var repo = DataAccess.EntityRepository;
var existingData = repo.All.Where(x => x.ParentId == parentId);  

TransactionScope scope = null;
try
{
    // this starts the outer transaction 
    using (scope = new TransactionScope(TransactionScopeOption.Required))
    {
        // this starts and commits an inner transaction
        existingData.Delete();

        // var toInsert = ... 

        // this relies on EntityFramework.BulkInsert library
        repo.BulkInsert(toInsert);

        // any other context changes can be performed

        // this starts and commit an inner transaction
        DataAccess.SaveChanges();

        // this commit the outer transaction
        scope.Complete();
    }
}
catch (Exception exc)
{
    // this also rollbacks any pending transactions
    scope?.Dispose();
}

其他回答

EntityFramework 6使用. removerange()使这变得更容易一些。

例子:

db.People.RemoveRange(db.People.Where(x => x.State == "CA"));
db.SaveChanges();

警告!不要在大型数据集上使用此方法!

EF将所有数据拉入内存,然后删除它。对于较小的数据集,这可能不是一个问题,但通常避免这种类型的删除,除非你能保证你只做非常小的更改。

您可以很容易地将进程运行到内存不足的状态,而EF会很高兴地提取您指定的所有数据来删除它。

如果需要删除表中的所有行,可以使用sql命令

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

TRUNCATE TABLE (Transact-SQL)从表中删除所有行,而不记录单个行删除。TRUNCATE TABLE类似于没有WHERE子句的DELETE语句;然而,TRUNCATE TABLE更快,使用更少的系统和事务日志资源。

在EF 6.2中,这可以很好地将删除直接发送到数据库,而无需首先加载实体:

context.Widgets.Where(predicate).Delete();

对于固定谓词,它非常简单:

context.Widgets.Where(w => w.WidgetId == widgetId).Delete();

如果你需要一个动态谓词,看看LINQKit (Nuget包可用),这样的东西在我的情况下工作得很好:

Expression<Func<Widget, bool>> predicate = PredicateBuilder.New<Widget>(x => x.UserID == userID);
if (somePropertyValue != null)
{
    predicate = predicate.And(w => w.SomeProperty == somePropertyValue);
}
context.Widgets.Where(predicate).Delete();

EF 6.=>

var assignmentAddedContent = dbHazirBot.tbl_AssignmentAddedContent.Where(a =>
a.HazirBot_CategoryAssignmentID == categoryAssignment.HazirBot_CategoryAssignmentID);
dbHazirBot.tbl_AssignmentAddedContent.RemoveRange(assignmentAddedContent);
dbHazirBot.SaveChanges();

Best: EF6 => . removerang ()

例子:

db.Table.RemoveRange(db.Table.Where(x => Field == "Something"));