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