Передача объекта на внедренный интерфейс в общий метод с использованием 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>();