Есть ли способ запретить Entity Framework НИКОГДА не читать записи, где свойство имеет значение c? - PullRequest
0 голосов
/ 04 марта 2020

У меня есть программное обеспечение, которое уже работает, сегодня наш клиент решил, что мы НЕ должны удалять какие-либо данные, а вместо этого скрываем их. Для этого я планирую добавить свойство «isDeleted» во все таблицы и изменить все методы удаления, чтобы вместо этого установить для этого свойства значение «true».

Проблема в том, что у меня в 1000 раз больше чтения, чем при удалении, Я могу иметь пользователя и пытаться читать все комментарии этого пользователя, используя отношение сущностей, я должен либо добавить «Где (x =>! X.isDeleted)» к каждому чтению, как это, либо, если это возможно, выбрать ВСЕ ВСЕ данные, которые isDeleted как истина от чтения.

Возможно ли последнее каким-либо образом? Если нет, есть ли альтернатива написанию «Где (x =>! X.isDeleted)» тысячу раз?

1 Ответ

2 голосов
/ 04 марта 2020

Я уже рассматривал эту проблему в прошлом, и откатить собственное решение гораздо сложнее, чем вы думали вначале, в основном потому, что действительно трудно изменить способ, которым операторы Include загружают связанные сущности (EF не ' действительно позволяет вам их фильтровать).

Но есть библиотека, которая может сделать это за вас.

Фильтрация результатов чтения

Это можно сделать довольно легко с помощью EntityFramework.DynamicFilters библиотека. (Я никоим образом не связан с разработчиками, мне просто очень нравится их библиотека)

Основной файл readme на самом деле имеет пример, который подходит для вашего случая использования:

modelBuilder.Filter("IsDeleted", (ISoftDelete d) => d.IsDeleted, false);

По сути, это будет возвращать только результаты Where(d => !d.IsDeleted), что именно то, что вы хотели бы. Этот фильтр применяется ко всем прямым выборкам и include, что означает, что эти мягко удаленные сущности, по сути, не существуют в том, что касается вашего домена.

Это предполагает, что ваши сущности все они происходят от общего root, имеющего флаг удаления, что я бы посоветовал вам сделать в любом случае.

Мягкое удаление объектов

Также возможно преобразовать жесткие удаления в мягкие удаления в контексте вашей базы данных, что означает, что вам не нужно переписывать код удаления, чтобы вместо этого обновить сущность (которая может быть громоздкой перепиской, и всегда возможно, что кто-то забудет ее здесь и там).

Вы можете переопределить поведение SaveChangesSaveChangesAsync) в своем классе контекста. Это позволяет вам найти все сущности, которые будут удалены, и дает вам возможность преобразовать это в оператор обновления, одновременно поднимая флаг IsDeleted.

Это также гарантирует, что никто не сможет забыть для мягкого удаления. Ваши разработчики могут просто жестко удалить объекты (при обработке кода), и контекст преобразует их для них.

public class MyContext : DbContext
{
    public override int SaveChanges()
    {
        ConvertHardDeleteToSoftDelete();

        return base.SaveChanges();
    }

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        ConvertHardDeleteToSoftDelete();

        return await base.SaveChangesAsync(cancellationToken);
    }

    private void ConvertHardDeleteToSoftDelete()
    {
        var deletedEntries = ChangeTracker
                                   .Entries<ISoftDelete>()
                                   .Where(entry => entry.State == EntityState.Deleted)
                                   .ToList();

        foreach (var entry in deletedEntries)
        {
            entry.State = EntityState.Modified;
            entry.IsDeleted = true;
        }
    }
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...