From 649985380cb3f359d110e86ec90a2b52fcd3b422 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 23:42:54 +0000 Subject: [PATCH 1/4] Fix #38315: use GetViewOrTableMappings for JSON container column lookup in SqlServer translator Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- ...rverQueryableMethodTranslatingExpressionVisitor.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs index f7e2368ff57..cf7c1a0a390 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal; using Microsoft.EntityFrameworkCore.SqlServer.Internal; @@ -537,13 +538,17 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr } } - // Find the container column in the relational model to get its type mapping + // Find the container column in the relational model to get its type mapping. + // Use GetViewOrTableMappings since the entity may be mapped to a view (ToView) rather than a table (see #38315), + // in which case GetTableMappings returns an empty sequence. // Note that we assume exactly one column with the given name mapped to the entity (despite entity splitting). // See #38060 about improving this. var containerColumnName = structuralType.GetContainerColumnName()!; - var containerColumn = structuralType.ContainingEntityType.GetTableMappings() +#pragma warning disable EF1001 // Internal EF Core API usage. + var containerColumn = structuralType.ContainingEntityType.GetViewOrTableMappings() .Select(m => m.Table.FindColumn(containerColumnName)) - .Single(c => c is not null)!; + .First(c => c is not null)!; +#pragma warning restore EF1001 var nestedJsonPropertyNames = jsonQueryExpression.StructuralType switch { From 4a776b6f9f80e87224261a8e79bf19710a49e8b8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 28 May 2026 00:15:02 +0000 Subject: [PATCH 2/4] Add regression test for #38315 Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Query/AdHocJsonQueryRelationalTestBase.cs | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryRelationalTestBase.cs index bbc85a26376..6ca55f6a2d9 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryRelationalTestBase.cs @@ -761,6 +761,74 @@ public Context37983_StringToIntConverter() #endregion + #region 38315 + + [Fact] + public virtual async Task Filter_on_complex_json_collection_on_entity_mapped_to_view() + { + var contextFactory = await InitializeNonSharedTest( + onConfiguring: b => b.ConfigureWarnings(ConfigureWarnings), + onModelCreating: m => + { + m.Entity(e => + { + e.ToTable("Persons"); + e.ComplexCollection(p => p.OrderIds, b => b.ToJson()); + }); + m.Entity(e => + { + e.ToView("PersonOrdersView"); + e.ComplexCollection(p => p.OrderIds, b => b.ToJson()); + }); + }, + seed: async context => + { + var sqlGenerationHelper = context.GetService(); + await context.Database.ExecuteSqlRawAsync( + $"CREATE VIEW {Q("PersonOrdersView")} AS SELECT {Q("Id")}, {Q("OrderIds")} FROM {Q("Persons")}"); + + context.Set().Add( + new Context38315.Person { OrderIds = [new Context38315.ValueJson { Value = 3 }] }); + await context.SaveChangesAsync(); + + string Q(string name) => sqlGenerationHelper.DelimitIdentifier(name); + }); + + await using var context = contextFactory.CreateDbContext(); + + var r = 3; + var result = await context.Set() + .Where(po => po.OrderIds.Any(oId => oId.Value == r)) + .ToListAsync(); + + Assert.Single(result); + } + + protected class Context38315(DbContextOptions options) : DbContext(options) + { + public DbSet Persons { get; set; } + public DbSet PersonOrdersViews { get; set; } + + public class Person + { + public int Id { get; set; } + public List OrderIds { get; set; } = []; + } + + public class PersonOrdersView + { + public int Id { get; set; } + public List OrderIds { get; set; } = []; + } + + public class ValueJson + { + public int Value { get; set; } + } + } + + #endregion 38315 + protected TestSqlLoggerFactory TestSqlLoggerFactory => (TestSqlLoggerFactory)ListLoggerFactory; From 5c002e9e8a10b3118275c19839e56a63d3826757 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 28 May 2026 00:15:57 +0000 Subject: [PATCH 3/4] Match #endregion convention Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../Query/AdHocJsonQueryRelationalTestBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryRelationalTestBase.cs index 6ca55f6a2d9..38360c1370a 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryRelationalTestBase.cs @@ -827,7 +827,7 @@ public class ValueJson } } - #endregion 38315 + #endregion protected TestSqlLoggerFactory TestSqlLoggerFactory => (TestSqlLoggerFactory)ListLoggerFactory; From 2833c773eed4cd0bf15e2c02e6d63cbac662eb4b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 28 May 2026 23:07:02 +0000 Subject: [PATCH 4/4] Remove extra comment lines from TransformJsonQueryToTable per review feedback Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../SqlServerQueryableMethodTranslatingExpressionVisitor.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs index cf7c1a0a390..8133d06fdea 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs @@ -539,8 +539,6 @@ protected override ShapedQueryExpression TransformJsonQueryToTable(JsonQueryExpr } // Find the container column in the relational model to get its type mapping. - // Use GetViewOrTableMappings since the entity may be mapped to a view (ToView) rather than a table (see #38315), - // in which case GetTableMappings returns an empty sequence. // Note that we assume exactly one column with the given name mapped to the entity (despite entity splitting). // See #38060 about improving this. var containerColumnName = structuralType.GetContainerColumnName()!;