Last active
          July 23, 2025 15:11 
        
      - 
      
- 
        Save haacked/febe9e88354fb2f4a4eb11ba88d64c24 to your computer and use it in GitHub Desktop. 
Revisions
- 
        haacked revised this gist Mar 23, 2021 . 1 changed file with 8 additions and 19 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -51,40 +51,29 @@ static void SetQueryFilter<TEntity, TEntityInterface>( var concreteExpression = filterExpression .Convert<TEntityInterface, TEntity>(); builder.Entity<TEntity>() .AppendQueryFilter(concreteExpression); } // CREDIT: This comment by magiak on GitHub https://github.com/dotnet/efcore/issues/10275#issuecomment-785916356 static void AppendQueryFilter<T>(this EntityTypeBuilder entityTypeBuilder, Expression<Func<T, bool>> expression) where T : class { var parameterType = Expression.Parameter(entityTypeBuilder.Metadata.ClrType); var expressionFilter = ReplacingExpressionVisitor.Replace( expression.Parameters.Single(), parameterType, expression.Body); if (entityTypeBuilder.Metadata.GetQueryFilter() != null) { var currentQueryFilter = entityTypeBuilder.Metadata.GetQueryFilter(); var currentExpressionFilter = ReplacingExpressionVisitor.Replace( currentQueryFilter.Parameters.Single(), parameterType, currentQueryFilter.Body); expressionFilter = Expression.AndAlso(currentExpressionFilter, expressionFilter); } var lambdaExpression = Expression.Lambda(expressionFilter, parameterType); entityTypeBuilder.HasQueryFilter(lambdaExpression); } } public static class ExpressionExtensions 
- 
        haacked revised this gist Aug 7, 2020 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,7 @@ /* Copyright Phil Haack Licensed under the MIT license - https://github.com/haacked/CodeHaacks/blob/main/LICENSE. */ using System; using System.Linq; using System.Linq.Expressions; 
- 
        haacked revised this gist Apr 30, 2020 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Query; public static class ModelBuilderExtensions { 
- 
        haacked revised this gist Apr 30, 2020 . 1 changed file with 9 additions and 0 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,12 @@ using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Remotion.Linq.Parsing.ExpressionVisitors; public static class ModelBuilderExtensions { static readonly MethodInfo SetQueryFilterMethod = typeof(ModelBuilderExtensions) 
- 
        haacked revised this gist Apr 30, 2020 . 1 changed file with 7 additions and 16 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,13 +1,3 @@ public static class ModelBuilderExtensions { static readonly MethodInfo SetQueryFilterMethod = typeof(ModelBuilderExtensions) @@ -23,7 +13,7 @@ public static void SetQueryFilterOnAllEntities<TEntityInterface>( .Select(t => t.ClrType) .Where(t => typeof(TEntityInterface).IsAssignableFrom(t))) { builder.SetEntityQueryFilter( type, filterExpression); } @@ -51,7 +41,7 @@ static void SetQueryFilter<TEntity, TEntityInterface>( .AddQueryFilter(concreteExpression); } // CREDIT: The AddQueryFilter and GetInternalEntityTypeBuilder methods come from this comment: // https://github.com/aspnet/EntityFrameworkCore/issues/10275#issuecomment-457504348 // And was written by https://github.com/YZahringer static void AddQueryFilter<T>(this EntityTypeBuilder entityTypeBuilder, Expression<Func<T, bool>> expression) @@ -61,19 +51,20 @@ static void AddQueryFilter<T>(this EntityTypeBuilder entityTypeBuilder, Expressi expression.Parameters.Single(), parameterType, expression.Body); var internalEntityTypeBuilder = entityTypeBuilder.GetInternalEntityTypeBuilder(); var queryFilter = internalEntityTypeBuilder?.Metadata.GetQueryFilter(); if (queryFilter != null) { var currentExpressionFilter = ReplacingExpressionVisitor.Replace( queryFilter.Parameters.Single(), parameterType, queryFilter.Body); expressionFilter = Expression.AndAlso(currentExpressionFilter, expressionFilter); } var lambdaExpression = Expression.Lambda(expressionFilter, parameterType); entityTypeBuilder.HasQueryFilter(lambdaExpression); } static InternalEntityTypeBuilder? GetInternalEntityTypeBuilder( this EntityTypeBuilder entityTypeBuilder) { var internalEntityTypeBuilder = typeof(EntityTypeBuilder) .GetProperty("Builder", BindingFlags.NonPublic | BindingFlags.Instance)? 
- 
        haacked revised this gist Aug 20, 2019 . 1 changed file with 3 additions and 0 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -51,6 +51,9 @@ static void SetQueryFilter<TEntity, TEntityInterface>( .AddQueryFilter(concreteExpression); } // The AddQueryFilter and GetInternalEntityTypeBuilder methods come from this comment: // https://github.com/aspnet/EntityFrameworkCore/issues/10275#issuecomment-457504348 // And was written by https://github.com/YZahringer static void AddQueryFilter<T>(this EntityTypeBuilder entityTypeBuilder, Expression<Func<T, bool>> expression) { var parameterType = Expression.Parameter(entityTypeBuilder.Metadata.ClrType); 
- 
        haacked revised this gist Aug 20, 2019 . 1 changed file with 35 additions and 10 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,8 +1,12 @@ using System; using System.Collections.ObjectModel; using System.Linq; using System.Linq.Expressions; using System.Reflection; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Remotion.Linq.Parsing.ExpressionVisitors; public static class ModelBuilderExtensions { @@ -44,16 +48,37 @@ static void SetQueryFilter<TEntity, TEntityInterface>( var concreteExpression = filterExpression .Convert<TEntityInterface, TEntity>(); builder.Entity<TEntity>() .AddQueryFilter(concreteExpression); } static void AddQueryFilter<T>(this EntityTypeBuilder entityTypeBuilder, Expression<Func<T, bool>> expression) { var parameterType = Expression.Parameter(entityTypeBuilder.Metadata.ClrType); var expressionFilter = ReplacingExpressionVisitor.Replace( expression.Parameters.Single(), parameterType, expression.Body); var internalEntityTypeBuilder = entityTypeBuilder.GetInternalEntityTypeBuilder(); if (internalEntityTypeBuilder.Metadata.QueryFilter != null) { var currentQueryFilter = internalEntityTypeBuilder.Metadata.QueryFilter; var currentExpressionFilter = ReplacingExpressionVisitor.Replace( currentQueryFilter.Parameters.Single(), parameterType, currentQueryFilter.Body); expressionFilter = Expression.AndAlso(currentExpressionFilter, expressionFilter); } var lambdaExpression = Expression.Lambda(expressionFilter, parameterType); entityTypeBuilder.HasQueryFilter(lambdaExpression); } static InternalEntityTypeBuilder GetInternalEntityTypeBuilder(this EntityTypeBuilder entityTypeBuilder) { var internalEntityTypeBuilder = typeof(EntityTypeBuilder) .GetProperty("Builder", BindingFlags.NonPublic | BindingFlags.Instance)? .GetValue(entityTypeBuilder) as InternalEntityTypeBuilder; return internalEntityTypeBuilder; } } public static class ExpressionExtensions { @@ -74,13 +99,13 @@ class ParameterTypeVisitor<TSource, TTarget> : ExpressionVisitor protected override Expression VisitParameter(ParameterExpression node) { return _parameters?.FirstOrDefault(p => p.Name == node.Name) ?? (node.Type == typeof(TSource) ? Expression.Parameter(typeof(TTarget), node.Name) : node); } protected override Expression VisitLambda<T>(Expression<T> node) { _parameters = VisitAndConvert(node.Parameters, "VisitLambda"); return Expression.Lambda(Visit(node.Body), _parameters); } } } 
- 
        haacked revised this gist Jul 29, 2019 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,6 +15,7 @@ public static void SetQueryFilterOnAllEntities<TEntityInterface>( Expression<Func<TEntityInterface, bool>> filterExpression) { foreach (var type in builder.Model.GetEntityTypes() .Where(t => t.BaseType == null) .Select(t => t.ClrType) .Where(t => typeof(TEntityInterface).IsAssignableFrom(t))) { 
- 
        haacked created this gist Jul 26, 2019 .There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,85 @@ using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; using Microsoft.EntityFrameworkCore; public static class ModelBuilderExtensions { static readonly MethodInfo SetQueryFilterMethod = typeof(ModelBuilderExtensions) .GetMethods(BindingFlags.NonPublic | BindingFlags.Static) .Single(t => t.IsGenericMethod && t.Name == nameof(SetQueryFilter)); public static void SetQueryFilterOnAllEntities<TEntityInterface>( this ModelBuilder builder, Expression<Func<TEntityInterface, bool>> filterExpression) { foreach (var type in builder.Model.GetEntityTypes() .Select(t => t.ClrType) .Where(t => typeof(TEntityInterface).IsAssignableFrom(t))) { builder.SetEntityQueryFilter<TEntityInterface>( type, filterExpression); } } static void SetEntityQueryFilter<TEntityInterface>( this ModelBuilder builder, Type entityType, Expression<Func<TEntityInterface, bool>> filterExpression) { SetQueryFilterMethod .MakeGenericMethod(entityType, typeof(TEntityInterface)) .Invoke(null, new object[] { builder, filterExpression }); } static void SetQueryFilter<TEntity, TEntityInterface>( this ModelBuilder builder, Expression<Func<TEntityInterface, bool>> filterExpression) where TEntityInterface : class where TEntity : class, TEntityInterface { var concreteExpression = filterExpression .Convert<TEntityInterface, TEntity>(); builder.Entity<TEntity>() .HasQueryFilter(concreteExpression); } } // ------------------------------------------------------- using System; using System.Collections.ObjectModel; using System.Linq; using System.Linq.Expressions; public static class ExpressionExtensions { // This magic is courtesy of this StackOverflow post. // https://stackoverflow.com/questions/38316519/replace-parameter-type-in-lambda-expression // I made some tweaks to adapt it to our needs - @haacked public static Expression<Func<TTarget, bool>> Convert<TSource, TTarget>( this Expression<Func<TSource, bool>> root) { var visitor = new ParameterTypeVisitor<TSource, TTarget>(); return (Expression<Func<TTarget, bool>>)visitor.Visit(root); } class ParameterTypeVisitor<TSource, TTarget> : ExpressionVisitor { private ReadOnlyCollection<ParameterExpression> _parameters; protected override Expression VisitParameter(ParameterExpression node) { return _parameters?.FirstOrDefault(p => p.Name == node.Name) ?? (node.Type == typeof(TSource) ? Expression.Parameter(typeof(TTarget), node.Name) : node); } protected override Expression VisitLambda<T>(Expression<T> node) { _parameters = VisitAndConvert<ParameterExpression>(node.Parameters, "VisitLambda"); return Expression.Lambda(Visit(node.Body), _parameters); } } }