如何使用 RemoveRange 与 1-query-approach Entity Framework 6
How to use RemoveRange with 1-query-approach Entity Framework 6
我正在寻找一种使用 1-query-approach 执行 RemoveRange()
的方法。使用 Remove()
方法,它的工作原理如下:
public void Delete()
{
Record record = new Record() {
id = 1,
value = 5
};
using(SomeContext ctx = new SomeContext()) {
ctx.Records.Entry(record).State = EntityState.Deleted;
ctx.SaveChanges();
}
}
但同样的方法不适用于 RemoveRange()
。 EF 文档说该方法将每个实体设置为 EntityState.Deleted
。如果是我理解的那样 - 这会起作用:
public void DeleteAll()
{
List<Record> records = new List<Record>() {
new Record() { id = 1, value = 5 },
new Record() { id = 2, value = 10 }
};
using(SomeContext ctx = new SomeContext()) {
ctx.Records.RemoveRange(records);
ctx.SaveChanges();
}
}
因为这行得通:
public void DeleteAll()
{
List<Record> records = new List<Record>() {
new Record() { id = 1, value = 5 },
new Record() { id = 2, value = 10 }
};
using(SomeContext ctx = new SomeContext()) {
foreach(var item in records)
{
ctx.Entry(item).State = EntityState.Deleted;
}
ctx.SaveChanges();
}
}
但它并没有抛出异常
The object cannot be deleted because it was not found in the ObjectStateManager.
我可以使用这种方法而不通过单独的查询从数据库中检索所有这些吗?
当您使用 ctx.Entry(item)
时,它会将此项目添加到上下文跟踪中,然后您可以对其进行编辑。使用 RemoveRange
它不会首先隐式添加到数据上下文,这就是您获得异常的原因。
尝试在 RemoveRange
之前使用 AttachRange
编辑:
另一种方法。这是 RemoveRange
在幕后的一些做法。它首先禁用 AutoDetectChanges
,删除它应该删除的内容,然后调用 DetectChanges
。可以将其包装在扩展方法中,使其再次成为一个衬里。
public void DeleteAll()
{
List<Record> records = new List<Record>() {
new Record() { id = 1, value = 5 },
new Record() { id = 2, value = 10 }
};
using(SomeContext ctx = new SomeContext()) {
ctx.Configuration.AutoDetectChangesEnabled = false;
foreach(var item in records)
{
ctx.Entry(item).State = EntityState.Deleted;
}
ctx.ChangeTracker.DetectChanges();
ctx.SaveChanges();
}
}
因为我发现你的实体集合是分离的(当你在那里创建它时)所以 objectContext 没有跟踪它。您可能需要附加它。您可以按如下方式执行此操作:
//Find all records in database with an id that is in your record collection
var recordsToBeDeleted = ctx.Records.Where(dbr => records.Any(r => r.id == dbr.id));
ctx.Records.RemoveRange(recordsToBeDeleted);
context.SaveChanges();
解决方案取自
我正在寻找一种使用 1-query-approach 执行 RemoveRange()
的方法。使用 Remove()
方法,它的工作原理如下:
public void Delete()
{
Record record = new Record() {
id = 1,
value = 5
};
using(SomeContext ctx = new SomeContext()) {
ctx.Records.Entry(record).State = EntityState.Deleted;
ctx.SaveChanges();
}
}
但同样的方法不适用于 RemoveRange()
。 EF 文档说该方法将每个实体设置为 EntityState.Deleted
。如果是我理解的那样 - 这会起作用:
public void DeleteAll()
{
List<Record> records = new List<Record>() {
new Record() { id = 1, value = 5 },
new Record() { id = 2, value = 10 }
};
using(SomeContext ctx = new SomeContext()) {
ctx.Records.RemoveRange(records);
ctx.SaveChanges();
}
}
因为这行得通:
public void DeleteAll()
{
List<Record> records = new List<Record>() {
new Record() { id = 1, value = 5 },
new Record() { id = 2, value = 10 }
};
using(SomeContext ctx = new SomeContext()) {
foreach(var item in records)
{
ctx.Entry(item).State = EntityState.Deleted;
}
ctx.SaveChanges();
}
}
但它并没有抛出异常
The object cannot be deleted because it was not found in the ObjectStateManager.
我可以使用这种方法而不通过单独的查询从数据库中检索所有这些吗?
当您使用 ctx.Entry(item)
时,它会将此项目添加到上下文跟踪中,然后您可以对其进行编辑。使用 RemoveRange
它不会首先隐式添加到数据上下文,这就是您获得异常的原因。
尝试在 RemoveRange
AttachRange
编辑:
另一种方法。这是 RemoveRange
在幕后的一些做法。它首先禁用 AutoDetectChanges
,删除它应该删除的内容,然后调用 DetectChanges
。可以将其包装在扩展方法中,使其再次成为一个衬里。
public void DeleteAll()
{
List<Record> records = new List<Record>() {
new Record() { id = 1, value = 5 },
new Record() { id = 2, value = 10 }
};
using(SomeContext ctx = new SomeContext()) {
ctx.Configuration.AutoDetectChangesEnabled = false;
foreach(var item in records)
{
ctx.Entry(item).State = EntityState.Deleted;
}
ctx.ChangeTracker.DetectChanges();
ctx.SaveChanges();
}
}
因为我发现你的实体集合是分离的(当你在那里创建它时)所以 objectContext 没有跟踪它。您可能需要附加它。您可以按如下方式执行此操作:
//Find all records in database with an id that is in your record collection
var recordsToBeDeleted = ctx.Records.Where(dbr => records.Any(r => r.id == dbr.id));
ctx.Records.RemoveRange(recordsToBeDeleted);
context.SaveChanges();
解决方案取自