我正在使用实体框架从表中删除几个项目。没有外键/父对象,所以我不能用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,对吧?
在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();
我知道已经很晚了,但如果有人需要一个简单的解决方案,最酷的事情是你还可以添加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);
}
这需要一点反思,但效果很好。
在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();
Thanh的回答最适合我。在一次服务器访问中删除了我所有的记录。我挣扎着实际调用扩展方法,所以我想分享我的(EF 6):
我将扩展方法添加到我的MVC项目中的一个助手类中,并将名称更改为“RemoveWhere”。我在控制器中注入了一个dbContext,但你也可以做一个using。
// make a list of items to delete or just use conditionals against fields
var idsToFilter = dbContext.Products
.Where(p => p.IsExpired)
.Select(p => p.ProductId)
.ToList();
// build the expression
Expression<Func<Product, bool>> deleteList =
(a) => idsToFilter.Contains(a.ProductId);
// Run the extension method (make sure you have `using namespace` at the top)
dbContext.RemoveWhere(deleteList);
这将为组生成一条delete语句。
实体框架核心
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.