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)
+ {
+ }
}