Provo ad applicare un filtro di query nel metodo OnModelCreating
(Entity Framework Core) per tutte le entità che hanno una proprietà ClientId
(int). Finora sono in grado di filtrare le entità ma faccio fatica a richiamare HasQueryFilter per quelle entità.
Il filtro deve confrontare la proprietà ClientId
dell'entità corrente con una proprietà da un servizio chiamato ITenantProvider
.
Ecco come lo faccio manualmente:
modelBuilder.Entity<MyEntity>().HasQueryFilter(a => a.ClientId == _tenantProvider.TenantId);
Sfortunatamente, il metodo EF Core HasQueryFilter
senza Generico prende una LambdaExpression
:
public virtual EntityTypeBuilder HasQueryFilter([CanBeNullAttribute] LambdaExpression filter);
Non so come posso tradurre la suddetta chiamata in un'espressione Lambda. Il mio codice attuale assomiglia a questo:
foreach (var entityType in modelBuilder.Model.GetEntityTypes().Where(e =>
e.GetProperties().Select(property => property.Name).Any(pName => pName.Equals("ClientId"))))
{
var clientId = entityType.FindProperty("ClientId");
if (clientId != null && clientId.ClrType == typeof(int))
{
var parameter = Expression.Parameter(entityType.ClrType, "p");
var filter = Expression.Lambda(Expression.Equal(Expression.Property(parameter, clientId.PropertyInfo), Expression.Constant(_tenantProvider.TenantId), parameter);
entityType.QueryFilter = filter;
}
}
Che funziona fondamentalmente per la prima chiamata ma dal momento che utilizzo Expression.Constant
non funziona per la richiesta successiva se il _tenantProvider.TenantId
cambia.
Come posso confrontare la proprietà Entity ClientId
con _tenantProvider.TenantId
in fase di runtime?
Il modo più semplice per ottenere l'espressione runtime equivalente di
_tenantProvider.TenantId
è quello di costruire un'espressione lambda senza parametri di compilazione e ottenere il suo corpo :
var parameter = Expression.Parameter(entityType.ClrType, "p");
var left = Expression.Property(parameter, clientId.PropertyInfo);
Expression<Func<int>> tenantId = () => _tenantProvider.TenantId;
var right = tenantId.Body;
var filter = Expression.Lambda(Expression.Equal(left, right), parameter);
Supponiamo che l'istanza di TenantProvider non cambi:
Poi invece dell'espressione costante che potresti usare
Expression.Property(Expression.Constant(_tenantProvider),"TenantId");
Se lo riattivi, a un certo punto questo non funzionerà più.
Supponiamo che tu abbia una proprietà statica che fornisce l'id tennant, quindi potresti usare:
Expression.MakeMemberAccess(null,typeof(TennantIdProvider).GetMember("CurrentId")[0]);