2015-08-12 3 views
1

Я никогда не хочу удалять строки из некоторых моих таблиц, поэтому я добавил столбец IsDeleted.Столбец Entity Framework IsDeleted или IsDisabled

POCS, которые представляют эти таблицы, реализуют интерфейс IDeleteable.

Когда я что-то вроде -

context.Users.Where(u => u.Firstname == "Dave") 

Я хочу получить обратно только те строки, которые не имеют IsDeleted бит.

Я не хочу, чтобы добавить && IsDeleted == false к Where

Я также хочу, чтобы это решение работать на Single, First, или просто context.Users и т.д.

Я хотел бы иметь что-то подобное решение к этому question.

+0

Этот проект может помочь вам: https://github.com/jcachat/EntityFramework.DynamicFilters и работает лучше, чем принятый ответ – trailmax

+0

Здесь вы найдете более отказоустойчивое решение: http://stackoverflow.com/questions/ 12698793/how-can-i-автоматически-filter-out-soft-deleted-entities-with-entity-framework – Laoujin

ответ

2

В свете комментария trailmax ниже да, исходный ответ ниже загружает все данные в память, так как он подвергает закодированным перечислениям.

Существует две проблемы, возникающие при попытке соединения IQueryable.

  1. EF не знаю, как перевести полученный .Invoke() вызов
  2. Если вы пытаетесь сохранить именовании как .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 через экземпляр вызов вместо как метод расширения, иначе вы будете работать в исключение переполнения стека.

+0

Я знаю, что я этого не говорил, но я бы хотел, чтобы это работало не просто как Where. Single, FirstOrDefault и т. Д. – Bryan

+0

Это невозможно. Они являются методами расширения и не могут быть переопределены, иначе вы получите неоднозначную ошибку вызова. –

+0

Каждый раз, когда я вижу «IEnumerable» в LINQ рядом с EF, я чувствую неприятности. Я думаю, что это может привести к фильтрации в памяти, а не фильтрации в базе данных. И на большом наборе это может быть очень плохо для производительности. Хотя я не пробовал/не подтвердил это, но это то, о чем нужно знать. – trailmax

0

Вы можете создать представление для каждой таблицы, в которой есть оператор where, действующий как его фильтр. Затем вы можете получить доступ к этому представлению из структуры сущностей вместо базовой таблицы и не беспокоиться об этом. Ваши пользователи никогда не знают о базовой таблице, просто в представлении.

Смежные вопросы