From c34a5a9814829af9123e43fdf751270cb0b7a4ce Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Feb 2026 17:10:14 +0000 Subject: [PATCH 1/3] Initial plan From 2ee81c6578e3cb7461d55e867241d605cf35614e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Feb 2026 17:19:23 +0000 Subject: [PATCH 2/3] Fix named query filter override from convention Pass ConfigurationSource.Explicit when creating QueryFilter in EntityTypeBuilder.HasQueryFilter(string, LambdaExpression) so that explicit configurations can override convention-set named query filters. Co-authored-by: roji <1862641+roji@users.noreply.github.com> --- .../Metadata/Builders/EntityTypeBuilder.cs | 2 +- .../Internal/InternalEntityTypeBuilderTest.cs | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs b/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs index 3a5f3b5826e..16d89c0f017 100644 --- a/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs +++ b/src/EFCore/Metadata/Builders/EntityTypeBuilder.cs @@ -822,7 +822,7 @@ public virtual EntityTypeBuilder HasQueryFilter(LambdaExpression? filter) /// The same builder instance so that multiple configuration calls can be chained. public virtual EntityTypeBuilder HasQueryFilter(string filterKey, LambdaExpression? filter) { - Builder.HasQueryFilter(new QueryFilter(filterKey, filter)); + Builder.HasQueryFilter(new QueryFilter(filterKey, filter, ConfigurationSource.Explicit)); return this; } diff --git a/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs b/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs index d6ad38bd6e1..e96a0e82c7f 100644 --- a/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs @@ -3392,6 +3392,31 @@ public void Can_replace_named_query_filter_only_with_lower_or_equal_source() Assert.NotEqual(filterExpression2, entityBuilder.Metadata.FindDeclaredQueryFilter(filterKey).Expression); } + [ConditionalFact] + public void Can_override_named_query_filter_from_convention_with_explicit_configuration() + { + // This test verifies that named query filters set by conventions can be overridden by explicit configuration + var modelBuilder = CreateModelBuilder(); + var entityBuilder = modelBuilder.Entity(typeof(Order), ConfigurationSource.Explicit); + + LambdaExpression conventionFilter = (Order o) => o.Id == 1; + LambdaExpression explicitFilter = (Order o) => o.Id == 2; + const string filterKey = "testFilter"; + + // Convention sets a named query filter + entityBuilder.HasQueryFilter(new QueryFilter(filterKey, conventionFilter, ConfigurationSource.Convention)); + Assert.Same(conventionFilter, entityBuilder.Metadata.FindDeclaredQueryFilter(filterKey).Expression); + Assert.Equal(ConfigurationSource.Convention, entityBuilder.Metadata.GetQueryFilterConfigurationSource(filterKey)); + + // Public API should be able to override it + var publicBuilder = new EntityTypeBuilder(entityBuilder.Metadata); + publicBuilder.HasQueryFilter(filterKey, explicitFilter); + + // Verify the filter was replaced with the explicit one + Assert.Same(explicitFilter, entityBuilder.Metadata.FindDeclaredQueryFilter(filterKey).Expression); + Assert.Equal(ConfigurationSource.Explicit, entityBuilder.Metadata.GetQueryFilterConfigurationSource(filterKey)); + } + private static TestLogger CreateTestLogger() => new() { EnabledFor = LogLevel.Warning }; From 0ed6b322ac368982817671c11afdb074940a98bb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 19:24:46 +0000 Subject: [PATCH 3/3] Make ConfigurationSource required in QueryFilter constructor Remove QueryFilter constructors that don't accept ConfigurationSource and make the ConfigurationSource property non-nullable. This ensures all QueryFilter instances have a valid configuration source for proper override behavior. Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- src/EFCore/Metadata/Internal/QueryFilter.cs | 41 +++++---------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/src/EFCore/Metadata/Internal/QueryFilter.cs b/src/EFCore/Metadata/Internal/QueryFilter.cs index 460e7065daf..1187c5983ef 100644 --- a/src/EFCore/Metadata/Internal/QueryFilter.cs +++ b/src/EFCore/Metadata/Internal/QueryFilter.cs @@ -8,7 +8,8 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal; /// /// The key of the query filter. /// The expression representing the filter. -public class QueryFilter(string? key, LambdaExpression? expression) : IQueryFilter +/// The configuration source of the query filter. +public class QueryFilter(string? key, LambdaExpression? expression, ConfigurationSource configurationSource) : IQueryFilter { /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -32,7 +33,7 @@ public class QueryFilter(string? key, LambdaExpression? expression) : IQueryFilt /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual ConfigurationSource? ConfigurationSource { get; set; } + public virtual ConfigurationSource ConfigurationSource { get; set; } = configurationSource; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -41,27 +42,7 @@ public class QueryFilter(string? key, LambdaExpression? expression) : IQueryFilt /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public QueryFilter(LambdaExpression? expression, ConfigurationSource configurationSource) - : this(null, expression) - => ConfigurationSource = configurationSource; - - /// - /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to - /// the same compatibility standards as public APIs. It may be changed or removed without notice in - /// any release. You should only use it directly in your code with extreme caution and knowing that - /// doing so can result in application failures when updating to a new Entity Framework Core release. - /// - public QueryFilter(string key, LambdaExpression? expression, ConfigurationSource configurationSource) - : this(key, expression) - => ConfigurationSource = configurationSource; - - /// - /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to - /// the same compatibility standards as public APIs. It may be changed or removed without notice in - /// any release. You should only use it directly in your code with extreme caution and knowing that - /// doing so can result in application failures when updating to a new Entity Framework Core release. - /// - public QueryFilter(LambdaExpression? expression) - : this(null, expression) + : this(null, expression, configurationSource) { } @@ -72,10 +53,9 @@ public QueryFilter(LambdaExpression? expression) /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public QueryFilter(string key, LambdaExpression? expression, bool fromDataAnnotation) - : this(key, expression) - => ConfigurationSource = fromDataAnnotation - ? Metadata.ConfigurationSource.DataAnnotation - : Metadata.ConfigurationSource.Convention; + : this(key, expression, fromDataAnnotation ? Metadata.ConfigurationSource.DataAnnotation : Metadata.ConfigurationSource.Convention) + { + } /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -84,8 +64,7 @@ public QueryFilter(string key, LambdaExpression? expression, bool fromDataAnnota /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public QueryFilter(LambdaExpression? expression, bool fromDataAnnotation) - : this(expression) - => ConfigurationSource = fromDataAnnotation - ? Metadata.ConfigurationSource.DataAnnotation - : Metadata.ConfigurationSource.Convention; + : this(null, expression, fromDataAnnotation ? Metadata.ConfigurationSource.DataAnnotation : Metadata.ConfigurationSource.Convention) + { + } }