Puis-je utiliser un cache de plan de requête distinct par session?

asp.net-mvc-4 c# entity-framework-6 entity-framework-plus

Question

J'ai une application ASP.NET à locataires multiples et notre base de données est configurée avec des suppressions logicielles. Initialement, nous avons géré la restriction des données directement au niveau de la requête, par exemple:

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

Comme vous pouvez l’imaginer, cela alourdit toutes les requêtes de notre couche d’accès aux données et rend l’API très vulnérable si l’on oublie d’ajouter les conditions de filtre correctes. Nous avons décidé d'appliquer le filtrage global au contexte avec Z.EntityFramework.Plus.EF6 :

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

Cela fonctionne parfaitement pour un utilisateur unique. Cependant, lorsque vous changez de client hébergé, nous rencontrons des problèmes d'enregistrement de l' expression de filtre dans le cache du plan de requête . Il s'agit d'un problème connu avec Entity Framework Plus et, comme il ne semble pas résolu, il faut trouver une solution de contournement.

La solution la plus immédiate à laquelle je puisse penser consiste à associer la durée de vie du cache du plan de requête à la session en cours. Lorsque l'utilisateur se déconnecte ou change de locataire, le cache est détruit. Est-ce possible, et si oui, comment puis-je y parvenir?

Réponse acceptée

J'ai eu exactement ce même problème et j'ai essayé de travailler avec Z.EntityFramework.Plus.EF6 avec les mêmes problèmes. J'ai découvert que l'équipe zzzprojects avait également EntityFramework.DynamicFilters, qui fonctionne beaucoup mieux à cette fin. La requête mise en cache est paramétrée et la valeur est injectée au moment de l'exécution à l'aide de la fonction de sélecteur fournie.

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; }
    }
}



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi