Передача объекта на внедренный интерфейс в общий метод с использованием LINQ для платформы Entity Framework

У меня есть общий метод для запроса объектов типа TEntity в EF. Я хочу добавить условие как предложение where, если TEntity реализует определенный интерфейс. У меня есть метод:

public TEntity GetByUserID(Guid userID)
{
    var query = this.DbSet;
    if (typeof (TEntity).IsImplementationOf<IDeletableEntity>())
    {
        query = query
            .Where((x => !((IDeletableEntity)x).IsDeleted);
    }
    return query
        .FirstOrDefault(x => x.UserID == userID);
}

IsImplementationOf < > () - метод, который возвращает true/false, как следует из названия.

Когда я запускаю это для адреса объекта, который реализует IDeletableEntity, я получаю сообщение об ошибке:

Невозможно ввести тип "Адрес", чтобы ввести "IDeletableEntity". LINQ to Entities поддерживает только листинг EDM примитивных или перечисляемых типов.

Любые идеи, как я могу обойти это ограничение LINQ?

Ответ 1

Это рабочее решение:

public TEntity GetByUserID(Guid userID, params Include<TEntity>[] includes)
{
    var query = this.DbSet;
    query = Where<IDeletableEntity>(query, x => !x.IsDeleted);
    return query
        .FirstOrDefault(x => x.UserID == userID);
}

public static IQueryable<TEntity> Where<TPredicateWellKnownType>(IQueryable<TEntity> query, Expression<Func<TPredicateWellKnownType, bool>> predicate)
{
    if (typeof(TEntity).IsImplementationOf<TPredicateWellKnownType>())
    {
        query = ((IQueryable<TPredicateWellKnownType>)query)
            .Where(predicate)
            .Cast<TEntity>();
    }
    return query;
}

Ответ 2

Если все DbSets имеют свойство UserID, затем создайте другой интерфейс с именем "IUserID", а затем попробуйте этот код:

    protected TEntity GetByUserID<TEntity>(Guid userID) where TEntity : class
    {
        var user = this.Set<TEntity>()
            .ToList()
            .Cast<IDeletableEntity>()
            .Where(u => (!u.IsDeleted))
            .Cast<IUserID>()
            .Where(u => (u.UserID == userID))
            .FirstOrDefault();
        return user;
    }

Ответ 3

Я думаю, что проблема может заключаться в том, что вы выполняете прямое действие в своем заявлении, а также в запросе могут быть перечислены типы перечисления, и поэтому IDeletable не реализуется как на одном объекте.

Проблема с линией LINQ-to-objects

предложил это решение.

 return query.ToList()
                       .Cast<IDeletable>()
                       .Where( e => e.Deleted )
                       .Cast<T>();