|
4 | 4 |
|
5 | 5 | namespace TinyHelpers.EntityFrameworkCore.Extensions; |
6 | 6 |
|
| 7 | +/// <summary> |
| 8 | +/// Provides extension methods for <see cref="ModelBuilder"/> to apply query filters and retrieve entity types. |
| 9 | +/// </summary> |
7 | 10 | public static class ModelBuilderExtensions |
8 | 11 | { |
| 12 | + /// <summary> |
| 13 | + /// Applies a global query filter to all entity types assignable to <typeparamref name="TEntity"/>. |
| 14 | + /// </summary> |
| 15 | + /// <typeparam name="TEntity">The base type or interface to match entity types against.</typeparam> |
| 16 | + /// <param name="modelBuilder">The <see cref="ModelBuilder"/> to apply the filter to.</param> |
| 17 | + /// <param name="expression">The filter expression to apply.</param> |
9 | 18 | public static void ApplyQueryFilter<TEntity>(this ModelBuilder modelBuilder, Expression<Func<TEntity, bool>> expression) |
| 19 | + { |
| 20 | + foreach (var clrType in modelBuilder.GetEntityTypes<TEntity>()) |
| 21 | + { |
| 22 | + var parameter = Expression.Parameter(clrType); |
| 23 | + var body = ReplacingExpressionVisitor.Replace(expression.Parameters.Single(), parameter, expression.Body); |
| 24 | + modelBuilder.Entity(clrType).HasQueryFilter(Expression.Lambda(body, parameter)); |
| 25 | + } |
| 26 | + } |
| 27 | + |
| 28 | + /// <summary> |
| 29 | + /// Applies a global query filter to all entity types that have a property with the specified name and type. |
| 30 | + /// </summary> |
| 31 | + /// <typeparam name="TType">The type of the property to filter on.</typeparam> |
| 32 | + /// <param name="modelBuilder">The <see cref="ModelBuilder"/> to apply the filter to.</param> |
| 33 | + /// <param name="propertyName">The name of the property to filter on.</param> |
| 34 | + /// <param name="value">The value to compare the property against.</param> |
| 35 | + public static void ApplyQueryFilter<TType>(this ModelBuilder modelBuilder, string propertyName, TType value) |
10 | 36 | { |
11 | 37 | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) |
12 | 38 | { |
13 | | - if (typeof(TEntity).IsAssignableFrom(entityType.ClrType)) |
| 39 | + var property = entityType.FindProperty(propertyName); |
| 40 | + if (property?.ClrType == typeof(TType)) |
14 | 41 | { |
15 | 42 | var parameter = Expression.Parameter(entityType.ClrType); |
16 | | - var body = ReplacingExpressionVisitor.Replace(expression.Parameters.Single(), parameter, expression.Body); |
17 | | - modelBuilder.Entity(entityType.ClrType).HasQueryFilter(Expression.Lambda(body, parameter)); |
| 43 | + var propertyAccess = Expression.Call(typeof(EF), nameof(EF.Property), [typeof(TType)], parameter, Expression.Constant(propertyName)); |
| 44 | + var filter = Expression.Lambda(Expression.Equal(propertyAccess, Expression.Constant(value, typeof(TType))), parameter); |
| 45 | + modelBuilder.Entity(entityType.ClrType).HasQueryFilter(filter); |
18 | 46 | } |
19 | 47 | } |
20 | 48 | } |
21 | 49 |
|
22 | | - public static void ApplyQueryFilter<TType>(this ModelBuilder modelBuilder, string propertyName, TType value) |
| 50 | +#if NET10_0_OR_GREATER |
| 51 | + /// <summary> |
| 52 | + /// Applies a named query filter to all entity types assignable to <typeparamref name="TEntity"/>. |
| 53 | + /// Named query filters can be selectively disabled at query time using <c>IgnoreQueryFilters</c>. |
| 54 | + /// </summary> |
| 55 | + /// <typeparam name="TEntity">The base type or interface to match entity types against.</typeparam> |
| 56 | + /// <param name="modelBuilder">The <see cref="ModelBuilder"/> to apply the filter to.</param> |
| 57 | + /// <param name="filterName">The name to assign to the query filter.</param> |
| 58 | + /// <param name="expression">The filter expression to apply.</param> |
| 59 | + /// <remarks> |
| 60 | + /// This feature requires .NET 10 or greater. Named query filters allow multiple filters per entity type |
| 61 | + /// and selective disabling via <c>IgnoreQueryFilters(["filterName"])</c>. |
| 62 | + /// See <see href="https://learn.microsoft.com/ef/core/querying/filters">EF Core Query Filters</see> for more information. |
| 63 | + /// </remarks> |
| 64 | + public static void ApplyQueryFilter<TEntity>(this ModelBuilder modelBuilder, string filterName, Expression<Func<TEntity, bool>> expression) |
| 65 | + { |
| 66 | + foreach (var clrType in modelBuilder.GetEntityTypes<TEntity>()) |
| 67 | + { |
| 68 | + var parameter = Expression.Parameter(clrType); |
| 69 | + var body = ReplacingExpressionVisitor.Replace(expression.Parameters.Single(), parameter, expression.Body); |
| 70 | + modelBuilder.Entity(clrType).HasQueryFilter(filterName, Expression.Lambda(body, parameter)); |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + /// <summary> |
| 75 | + /// Applies a named query filter to all entity types that have a property with the specified name and type. |
| 76 | + /// Named query filters can be selectively disabled at query time using <c>IgnoreQueryFilters</c>. |
| 77 | + /// </summary> |
| 78 | + /// <typeparam name="TType">The type of the property to filter on.</typeparam> |
| 79 | + /// <param name="modelBuilder">The <see cref="ModelBuilder"/> to apply the filter to.</param> |
| 80 | + /// <param name="filterName">The name to assign to the query filter.</param> |
| 81 | + /// <param name="propertyName">The name of the property to filter on.</param> |
| 82 | + /// <param name="value">The value to compare the property against.</param> |
| 83 | + /// <remarks> |
| 84 | + /// This feature requires .NET 10 or greater. Named query filters allow multiple filters per entity type |
| 85 | + /// and selective disabling via <c>IgnoreQueryFilters(["filterName"])</c>. |
| 86 | + /// See <see href="https://learn.microsoft.com/ef/core/querying/filters">EF Core Query Filters</see> for more information. |
| 87 | + /// </remarks> |
| 88 | + public static void ApplyQueryFilter<TType>(this ModelBuilder modelBuilder, string filterName, string propertyName, TType value) |
23 | 89 | { |
24 | 90 | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) |
25 | 91 | { |
26 | 92 | var property = entityType.FindProperty(propertyName); |
27 | 93 | if (property?.ClrType == typeof(TType)) |
28 | 94 | { |
29 | 95 | var parameter = Expression.Parameter(entityType.ClrType); |
30 | | - var filter = Expression.Lambda(Expression.Equal(Expression.Property(parameter, propertyName), Expression.Constant(value)), parameter); |
31 | | - modelBuilder.Entity(entityType.ClrType).HasQueryFilter(filter); |
| 96 | + var propertyAccess = Expression.Call(typeof(EF), nameof(EF.Property), [typeof(TType)], parameter, Expression.Constant(propertyName)); |
| 97 | + var filter = Expression.Lambda(Expression.Equal(propertyAccess, Expression.Constant(value, typeof(TType))), parameter); |
| 98 | + modelBuilder.Entity(entityType.ClrType).HasQueryFilter(filterName, filter); |
32 | 99 | } |
33 | 100 | } |
34 | 101 | } |
| 102 | +#endif |
35 | 103 |
|
| 104 | + /// <summary> |
| 105 | + /// Gets all entity types in the model that are assignable to <typeparamref name="TType"/>. |
| 106 | + /// </summary> |
| 107 | + /// <typeparam name="TType">The base type or interface to match entity types against.</typeparam> |
| 108 | + /// <param name="modelBuilder">The <see cref="ModelBuilder"/> to query.</param> |
| 109 | + /// <returns>An enumerable of CLR types that are assignable to <typeparamref name="TType"/>.</returns> |
36 | 110 | public static IEnumerable<Type> GetEntityTypes<TType>(this ModelBuilder modelBuilder) |
37 | 111 | => GetEntityTypes(modelBuilder, typeof(TType)); |
38 | 112 |
|
| 113 | + /// <summary> |
| 114 | + /// Gets all entity types in the model that are assignable to the specified <paramref name="baseType"/>. |
| 115 | + /// </summary> |
| 116 | + /// <param name="modelBuilder">The <see cref="ModelBuilder"/> to query.</param> |
| 117 | + /// <param name="baseType">The base type or interface to match entity types against.</param> |
| 118 | + /// <returns>An enumerable of CLR types that are assignable to <paramref name="baseType"/>.</returns> |
39 | 119 | public static IEnumerable<Type> GetEntityTypes(this ModelBuilder modelBuilder, Type baseType) |
40 | 120 | { |
41 | 121 | var entityTypes = modelBuilder.Model.GetEntityTypes() |
42 | | - .Where(t => baseType.IsAssignableFrom(t.ClrType)) |
| 122 | + .Where(t => t.ClrType.IsAssignableTo(baseType)) |
43 | 123 | .ToList(); |
44 | 124 |
|
45 | 125 | return entityTypes.Select(t => t.ClrType); |
|
0 commit comments