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


当前回答

从服务器上拉回任何东西来删除它看起来仍然很疯狂,但至少只返回id比拉下完整的实体要精简得多:

var ids = from w in context.Widgets where w.WidgetId == widgetId select w.Id;
context.Widgets.RemoveRange(from id in ids.AsEnumerable() select new Widget { Id = id });

其他回答

我知道已经很晚了,但如果有人需要一个简单的解决方案,最酷的事情是你还可以添加where子句:

public static void DeleteWhere<T>(this DbContext db, Expression<Func<T, bool>> filter) where T : class
{
    string selectSql = db.Set<T>().Where(filter).ToString();
    string fromWhere = selectSql.Substring(selectSql.IndexOf("FROM"));
    string deleteSql = "DELETE [Extent1] " + fromWhere;
    db.Database.ExecuteSqlCommand(deleteSql);
}

注意:刚刚用MSSQL2008测试过。

更新:

上面的解决方案不会工作时,EF生成sql语句的参数,所以这里是EF5的更新:

public static void DeleteWhere<T>(this DbContext db, Expression<Func<T, bool>> filter) where T : class
{
    var query = db.Set<T>().Where(filter);

    string selectSql = query.ToString();
    string deleteSql = "DELETE [Extent1] " + selectSql.Substring(selectSql.IndexOf("FROM"));

    var internalQuery = query.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(field => field.Name == "_internalQuery").Select(field => field.GetValue(query)).First();
    var objectQuery = internalQuery.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(field => field.Name == "_objectQuery").Select(field => field.GetValue(internalQuery)).First() as ObjectQuery;
    var parameters = objectQuery.Parameters.Select(p => new SqlParameter(p.Name, p.Value)).ToArray();

    db.Database.ExecuteSqlCommand(deleteSql, parameters);
}

这需要一点反思,但效果很好。

从服务器上拉回任何东西来删除它看起来仍然很疯狂,但至少只返回id比拉下完整的实体要精简得多:

var ids = from w in context.Widgets where w.WidgetId == widgetId select w.Id;
context.Widgets.RemoveRange(from id in ids.AsEnumerable() select new Widget { Id = id });

实体框架核心

3.1 3.0 2.2 2.1 2.0 1.1 1.0

using (YourContext context = new YourContext ())
{
    var widgets = context.Widgets.Where(w => w.WidgetId == widgetId);
    context.Widgets.RemoveRange(widgets);
    context.SaveChanges();
}

简介:

从集合下面的上下文中移除给定的实体集合 每个实体都处于已删除状态,这样它就会被删除 当SaveChanges被调用时,从数据库中获取。

备注:

Note that if System.Data.Entity.Infrastructure.DbContextConfiguration.AutoDetectChangesEnabled is set to true (which is the default), then DetectChanges will be called once before delete any entities and will not be called again. This means that in some situations RemoveRange may perform significantly better than calling Remove multiple times would do. Note that if any entity exists in the context in the Added state, then this method will cause it to be detached from the context. This is because an Added entity is assumed not to exist in the database such that trying to delete it does not make sense.

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

context.Widgets.Delete(w => w.WidgetId == widgetId);
 context.Widgets.RemoveRange(context.Widgets.Where(w => w.WidgetId == widgetId).ToList());
                db.SaveChanges();