LINQ-to-entities casting issue

2020-04-21 09:13发布

问题:

I'm trying to filter a LINQ-to-entities query in a generic way, but I keep getting an error. Here is a piece of code:

private IQueryable<T> FilterDeletedEntities<T>(IQueryable<T> entities)
{
    if (typeof(IDeletable).IsAssignableFrom(typeof(T)))
    {
        var deletableEntities = (IQueryable<IDeletable>)entities;
        deletableEntities = deletableEntities.Where(entity => !entity.Deleted);
        entities = (IQueryable<T>)deletableEntities;
    }
    return entities;
}

Basically I'm trying to filter out deleted entities (i.e. 'Deleted' field is 'true'), if and only if the entity is IDeletable (i.e. it has the 'Deleted' field). The problem is that I can't cast IQueryable< IDeletable > back to IQueryable< T >.

Any ideas on how to fix this? And before you ask: yes, this method has to be generic.

Thanks in advance!

回答1:

But you can use Cast<T>() to convert it.

 entities = deletableEntities.Cast<T>();

You could also use it to case to IDeletable as well, for example,

private IEnumerable<T> FilterDeletedEntities<T>(IQueryable<T> entities)
{
    if (typeof(IDeletable).IsAssignableFrom(typeof(T)))
    {
        return entities.ToList()
                       .Cast<IDeletable>()
                       .Where( e => !e.Deleted )
                       .Cast<T>();
    }
    return entities.ToList();
}


回答2:

I was able to solve my problem by doing this:

private IQueryable<T> FilterDeletedEntities<T>(IQueryable<T> entities)
{
    if (typeof(IDeletable).IsAssignableFrom(typeof(T)))
    {
        var deletableEntities = (IQueryable<IDeletable>)entities;
        return deletableEntities.Where(entity => !entity.Deleted).Cast<T>();
    }
    return entities;
}

Thanks to tvanfosson for the inspiration.



回答3:

If you can assume that no one will need to call this method with T that does not implement IDeletable, you can restrict T:

private IQueryable<T> FilterDeletedEntities<T>(IQueryable<T> entities) where T : IDeletable

As a bonus, you won't need to cast anything or use reflection to test for IDeletable.