В свете комментария trailmax ниже да, исходный ответ ниже загружает все данные в память, так как он подвергает закодированным перечислениям.
Существует две проблемы, возникающие при попытке соединения IQueryable
.
- EF не знаю, как перевести полученный
.Invoke()
вызов
- Если вы пытаетесь сохранить именовании как
.Where()
, вы будете в конечном итоге выбор неправильный расширение, так как IDeletable
только выставляет один столбец, на котором вы можете построить предикат.
Следующая статья ссылается на библиотеку LinqKit на выражения цепочки, и синтаксис уже не является текучим, но он предотвращает немедленное выполнение.
var users = context.Users.WhereIsNotDeleted(x => x.Id > 0).ToList();
public static class Extension
{
public static IEnumerable<T> WhereIsNotDeleted<T>(this IQueryable<T> source,
Expression<Func<T, bool>> predicate) where T : IDeletable
{
var query = source.AsExpandable().Where(x => !x.IsDeleted);
return query.Where(predicate);
}
}
Предполагая, что IDeletable
гарантии IsDeleted
существует, вы можете создать метод расширения, который всегда выполняет эту проверку для вас.
public interface IDeletable
{
bool IsDeleted { get; set; }
}
public static class Extension
{
public static IEnumerable<T> WhereNotDeleted<T>(this IEnumerable<T> source,
Func<T, bool> predicate) where T : IDeletable
{
return source.Where(x => !x.IsDeleted).Where(predicate);
}
}
В следующем простом испытании возвращаются только две записи, так как третья была мягко удалена.
void Main()
{
var x = new List<Test>();
x.Add(new Test{ Number = "one" });
x.Add(new Test{ Number = "two" });
x.Add(new Test{ Number = "three", IsDeleted = true });
var y = x.WhereNotDeleted(a => a != null);
y.Count().Dump();
}
public class Test : IDeletable
{
public string Number { get; set; }
public bool IsDeleted { get; set; }
}
В свете своего комментария, если вы хотите его для работы с существующими методами расширения LINQ, вы на самом деле не в состоянии, так как вы столкнетесь с неоднозначностью вызова.
Если вы хотите позвонить .Where()
и перевести его в свое состояние ТОЛЬКО для ваших объектов, которые реализуют IDeletable
, вам нужно будет обернуть каждый метод расширения LINQ.
public static class Extension
{
public static IEnumerable<IDeletable> Where(this IEnumerable<IDeletable> source,
Func<IDeletable, bool> predicate)
{
return System.Linq.Enumerable.Where(source, (x => predicate(x) && !x.IsDeleted));
}
}
В этих методах расширения вы должны вызывать методы базового LINQ через экземпляр вызов вместо как метод расширения, иначе вы будете работать в исключение переполнения стека.
Этот проект может помочь вам: https://github.com/jcachat/EntityFramework.DynamicFilters и работает лучше, чем принятый ответ – trailmax
Здесь вы найдете более отказоустойчивое решение: http://stackoverflow.com/questions/ 12698793/how-can-i-автоматически-filter-out-soft-deleted-entities-with-entity-framework – Laoujin