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();
}
Другие вопросы по тегам