简体   繁体   中英

DBSet.Where(…).Delete() -> “no matching element” which is not true

I am using EF 6.1 with EF.Extended and I am trying to execute the following:

if (allRevisions != null && allRevisions.Any(r => r.Item.Id == itemId))
    allRevisions.Where(r => r.Item.Id == itemId).Delete();

allRevisions is a DbSet<Revision> from my current DbContext (this code is inside a generic helper method).
When I execute this I get the following exception:

Sequence contains no matching element.

Which is not true as there is a matching revision and the Any is also true.
Furthermore if I execute the following it works fine:

if (allRevisions != null && allRevisions.Any(r => r.Item.Id == itemId))
{
    foreach (var revision in allRevisions.Where(r => r.Item.Id == itemId))
        allRevisions.Remove(revision);
}

But that is exactly the way you should be able to avoid with EF.Extended.

Am I doing something wrong or is this a bug in EF.Extended?

PS: I know that the Any is pointless - I added that to make shure there are revisions to delete after I got the error the first time. There is also no race-condition as on my dev-machine no one else is hitting the DB.
Better to materialize the query then check if it has items and delete those you need to delete all in memory. => but thats exactly what I want to avoid (and what EF.Extened is good for). I actually don't care if something has changed - I would expect it to simply execute a query like DELETE from Revisions WHERE Item_Id = @Id; in the DB.

UPDATE:
I created a small demo-project to reproduce the problem: HERE
It seems to be connected to inheritance. If I try the same thing with the ContentRevision it works, but with MyRevision , which inherits from it, it does not.

I faced the same problem. So I used your example to locate the issue. It seems to be in inheritance. In class MetadataMappingProvider is following code

        // 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);

and the second Single seems to be the trouble, because in EntitySets property are just entity sets for base classes. There is a simple solution to this problem. Always use the base class (from EF point of view) in query. For example if we have following mapping:

    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; }
}

this code will throw an error:

    using (var context = new TestContext())
{
    context.Items.OfType<ItemWithContent>()
        .Where(o => string.IsNullOrWhiteSpace(o.Content)).Delete();
}

but this code will work correctly:

using (var context = new TestContext())
{
    context.Items
        .Where(o => o is ItemWithContent && 
            string.IsNullOrWhiteSpace((o as ItemWithContent).Content)).Delete();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM