Можно ли использовать отдельный кеш-план запроса для сеанса?


Вопрос

У меня многопользовательское приложение ASP.NET, и наша база данных настроена с мягкими удалениями. Первоначально мы обрабатывали ограничение данных непосредственно на уровне запроса, например:

var foos = context.Foos.Where(foo => !foo.Deleted && foo.TenantId = currentTenantId).ToList();

Как вы можете себе представить, это раздувает все запросы на нашем уровне доступа к данным и делает API очень уязвимым, если вы забываете добавлять правильные условия фильтра. Мы решили применить глобальную фильтрацию к контексту с помощью Z.EntityFramework.Plus.EF6 :

var foos = context.Foos.Where(foo => !foo.Deleted && foo.TenantId = currentTenantId).ToList();

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

Самое непосредственное решение, о котором я могу думать, - связать время жизни кеша плана запроса с текущим сеансом, а когда пользователь выходит из системы или переключает арендатора, кеш уничтожается. Возможно ли это, и если да, то как я могу это достичь?

Принятый ответ

У меня была такая же проблема и я попытался работать с Z.EntityFramework.Plus.EF6 с теми же проблемами. Я обнаружил, что команда zzzprojects также имеет EntityFramework.DynamicFilters, которая работает намного лучше для этой цели. Запрос, который кэшируется, параметризуется, и значение вводится во время выполнения с использованием функции селектора, которую вы предоставляете.

using System.Data.Entity;
using EntityFramework.DynamicFilters;

public class Program
{   
    public class CustomContext : DbContext
    {
        private int _tenantId;

        public int GetTenantId()
        {
            return _tenantId;
        }

        // Call this function to set the tenant once authentication is complete.
        // Alternatively, you could pass tenantId in when constructing CustomContext if you already know it
        // or pass in a function that returns the tenant to the constructor and call it here.
        public void SetTenantId(int tenantId)
        {
            _tenantId = tenantId;
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            // Filter applies to any model that implements ITenantRestrictedObject
            modelBuilder.Filter(
                "TenantFilter",
                (ITenantRestrictedObject t, int tenantId) => t.TenantId == tenantId,
                (CustomContext ctx) => ctx.GetTenantId(), // Might could replace this with a property accessor... I haven't tried it
                opt => opt.ApplyToChildProperties(false)
            );
        }
    }

    public interface ITenantRestrictedObject
    {
        int TenantId { get; }
    }
}




Лицензировано согласно: CC-BY-SA
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему