DBSet.Where(...).Delete() -> "нет соответствующего элемента", что не соответствует действительности
Я использую EF 6.1 с EF.Extended и пытаюсь выполнить следующее:
if (allRevisions != null && allRevisions.Any(r => r.Item.Id == itemId))
allRevisions.Where(r => r.Item.Id == itemId).Delete();
allRevisions
это DbSet<Revision>
из моего текущего DbContext
(этот код находится внутри общего вспомогательного метода).
Когда я выполняю это, я получаю следующее исключение:
Последовательность не содержит соответствующего элемента.
Что не соответствует действительности, так как есть соответствующая ревизия и Any
тоже верно.
Кроме того, если я выполню следующее, он будет работать нормально:
if (allRevisions != null && allRevisions.Any(r => r.Item.Id == itemId))
{
foreach (var revision in allRevisions.Where(r => r.Item.Id == itemId))
allRevisions.Remove(revision);
}
Но это именно то, чего вы должны избегать с EF.Extended.
Я делаю что-то не так или это ошибка в EF.Extended?
PS: я знаю, что Any
Бессмысленно - я добавил, что для уверенности есть ревизии, которые нужно удалить после того, как я получил ошибку в первый раз. Также нет условий гонки, так как на моей dev-машине больше никто не бьет по БД.Better to materialize the query then check if it has items and delete those you need to delete all in memory.
=> но это именно то, чего я хочу избежать (и для чего хорош EF.Exened). Я на самом деле не волнуюсь, если что-то изменилось - я ожидал бы, что это просто выполнить запрос, как DELETE from Revisions WHERE Item_Id = @Id;
в БД.
ОБНОВИТЬ:
Я создал небольшой демо-проект для воспроизведения проблемы: ЗДЕСЬ
Кажется, это связано с наследованием. Если я попробую то же самое с ContentRevision
это работает, но с MyRevision
, который наследует от него, это не так.
1 ответ
Я столкнулся с той же проблемой. Поэтому я использовал ваш пример, чтобы найти проблему. Вроде в наследство. В классе MetadataMappingProvider есть следующий код
// Get the entity set that uses this entity type
var entitySet = metadata
.GetItems<EntityContainer>(DataSpace.CSpace)
.Single()
.EntitySets
.Single(s => s.ElementType.Name == entityType.Name);
и второй Single кажется проблемой, потому что в свойстве EntitySets просто наборы сущностей для базовых классов. Существует простое решение этой проблемы. Всегда используйте базовый класс (с точки зрения EF) в запросе. Например, если у нас есть следующее отображение:
public class Item
{
public long Id { get; set; }
}
public class ItemWithContent : Item
{
public string Content { get; set; }
}
public class TestContext : DbContext
{
public IDbSet<Item> Items { get; set; }
}
этот код выдаст ошибку:
using (var context = new TestContext())
{
context.Items.OfType<ItemWithContent>()
.Where(o => string.IsNullOrWhiteSpace(o.Content)).Delete();
}
но этот код будет работать правильно:
using (var context = new TestContext())
{
context.Items
.Where(o => o is ItemWithContent &&
string.IsNullOrWhiteSpace((o as ItemWithContent).Content)).Delete();
}