diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs index f7e2368ff57..8133d06fdea 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,15 @@ 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. // 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 { diff --git a/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/AdHocJsonQueryRelationalTestBase.cs index bbc85a26376..38360c1370a 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 + protected TestSqlLoggerFactory TestSqlLoggerFactory => (TestSqlLoggerFactory)ListLoggerFactory;