我正在使用实体框架从表中删除几个项目。没有外键/父对象,所以我不能用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,对吧?


当前回答

using (var context = new DatabaseEntities())
{
    context.ExecuteStoreCommand("DELETE FROM YOURTABLE WHERE CustomerID = {0}", customerId);
}

新增:支持可编写的id列表

var listOfIds = String.Join(',',customerIds.Select(id => $"'{id}'").ToList());
var sql= $@"DELETE  [YOURTABLE] WHERE CustomerID in ({listOfIds})";

注意:如果CustomerID是一个字符串,您应该仔细检查潜在的SQL注入风险,对于整数CustomerID是安全的

其他回答

这已经够好了,对吧?我可以用扩展来抽象它 方法或助手,但我们还是会用到 foreach ?

是的,不过你可以把它写成两行字:

context.Widgets.Where(w => w.WidgetId == widgetId)
               .ToList().ForEach(context.Widgets.DeleteObject);
context.SaveChanges();

请看答案“最喜欢的代码”

下面是我如何使用它:

     // Delete all rows from the WebLog table via the EF database context object
    // using a where clause that returns an IEnumerable typed list WebLog class 
    public IEnumerable<WebLog> DeleteAllWebLogEntries()
    {
        IEnumerable<WebLog> myEntities = context.WebLog.Where(e => e.WebLog_ID > 0);
        context.WebLog.RemoveRange(myEntities);
        context.SaveChanges();

        return myEntities;
    }

如果您正在使用通用存储库:

在泛型存储库中,下面可能是新方法。

       public void RemoveMultiple(Expression<Func<T, bool>> predicate)
        {
             IQueryable<T> query = _context.Set<T>().Where(predicate);
             _context.Set<T>().RemoveRange(query.AsNoTracking());
            
        }

用法:

_unitOfWork.YOUR_ENTITY.RemoveMultiple(x => x.AccountId == accountId);
 _unitOfWork.Complete();

如果你不想直接执行SQL,在循环中调用DeleteObject是最好的方法。

但是,您可以使用我在这里描述的方法,通过扩展方法执行SQL,并使其完全通用。

尽管答案是3.5。对于4.0,我可能会在底层使用新的ExecuteStoreCommand API,而不是下拉到StoreConnection。

对于任何使用EF5的人,可以使用以下扩展库:https://github.com/loresoft/EntityFramework.Extended

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