세션별로 별도의 쿼리 계획 캐시를 사용할 수 있습니까?


문제

멀티 테넌트 (multi-tenant) ASP.NET 응용 프로그램이 있고 데이터베이스가 소프트 삭제로 설정되어 있습니다. 처음에는 쿼리 수준에서 직접 데이터 제한을 처리했습니다 (예 :

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

상상할 수 있듯이이 API는 데이터 액세스 레이어의 모든 쿼리를 압축하고 올바른 필터 조건을 추가하는 것을 잊어 버리면 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
이 KB는 합법적입니까? 예, 이유를 알아보십시오.