我正在使用实体框架从表中删除几个项目。没有外键/父对象,所以我不能用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,对吧?
我知道已经很晚了,但如果有人需要一个简单的解决方案,最酷的事情是你还可以添加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);
}
这需要一点反思,但效果很好。
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是安全的
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();
}
在EF 7中,您可以使用批量删除
var ids = widgets.Select(x => x.Id).ToList();
await _mrVodDbContext.Widgets.Where(x => ids.Contains(x.Id)).ExecuteDeleteAsync();
EF磁芯发生器
DELETE FROM [i]
FROM [Widgets] AS [i]
WHERE [i].[Id] IN (4,3,2,1)
更多关于在发行说明中删除或更新的信息。https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/whatsnew#basic-executedelete-examples
实体框架核心
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.