From be7d33121d2f20816d67b4cb749f184180351b91 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 20 Jun 2023 11:35:11 +0200 Subject: [PATCH] Partial fix to type mapping inference for primitive collections Closes #31030 --- All.sln.DotSettings | 1 + ...yableMethodTranslatingExpressionVisitor.cs | 6 ++- ...dPrimitiveCollectionsQuerySqlServerTest.cs | 46 +++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/All.sln.DotSettings b/All.sln.DotSettings index edd36d48c74..8ed3bce7378 100644 --- a/All.sln.DotSettings +++ b/All.sln.DotSettings @@ -335,6 +335,7 @@ The .NET Foundation licenses this file to you under the MIT license. True True True + True True True True diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index bc8643d363d..82f80a6d8bc 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -2656,6 +2656,7 @@ when _currentSelectExpression is not null && _currentProjectionExpression is not null && _inferredColumns.TryGetValue( (_currentSelectExpression, _currentProjectionExpression.Alias), out var inferredTypeMapping) + && inferredTypeMapping is not null && WasMaybeOriginallyUntyped(columnExpression): { RegisterInferredTypeMapping(columnExpression, inferredTypeMapping); @@ -2704,14 +2705,15 @@ SqlExpression UnwrapConvert(SqlExpression expression) : expression; } - private void RegisterInferredTypeMapping(ColumnExpression columnExpression, RelationalTypeMapping? inferredTypeMapping) + private void RegisterInferredTypeMapping(ColumnExpression columnExpression, RelationalTypeMapping inferredTypeMapping) { var underlyingTable = columnExpression.Table is JoinExpressionBase joinExpression ? joinExpression.Table : columnExpression.Table; if (_inferredColumns.TryGetValue((underlyingTable, columnExpression.Name), out var knownTypeMapping) - && inferredTypeMapping != knownTypeMapping) + && knownTypeMapping is not null + && inferredTypeMapping.StoreType != knownTypeMapping.StoreType) { // A different type mapping was already inferred for this column - we have a conflict. // Null out the value for the inferred type mapping as an indication of the conflict. If it turns out that we need the diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs index b22f075752d..acd4773538b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs @@ -313,6 +313,52 @@ FROM OPENJSON(@__dateTimes_0_1) WITH ([value] datetime2 '$') AS [d0] """); } + [ConditionalFact] + public virtual async Task Same_collection_with_default_type_mapping_and_uninferrable_context() + { + var contextFactory = await InitializeAsync( + onModelCreating: mb => mb.Entity(b => b.Property(typeof(DateTime), "DateTime"))); + + await using var context = contextFactory.CreateContext(); + + var dateTimes = new DateTime?[] { new DateTime(2020, 1, 1, 12, 30, 00), new DateTime(2020, 1, 2, 12, 30, 00), null }; + + _ = await context.Set() + .Where(m => dateTimes.Any(d => d == EF.Property(m, "DateTime") && d != null)) + .ToArrayAsync(); + + AssertSql( +""" +@__dateTimes_0='["2020-01-01T12:30:00","2020-01-02T12:30:00",null]' (Size = 4000) + +SELECT [t].[Id], [t].[DateTime], [t].[Ints] +FROM [TestEntity] AS [t] +WHERE EXISTS ( + SELECT 1 + FROM OPENJSON(@__dateTimes_0) WITH ([value] datetime2 '$') AS [d] + WHERE [d].[value] = [t].[DateTime] AND [d].[value] IS NOT NULL) +"""); + } + + [ConditionalFact] + public virtual async Task Same_collection_with_non_default_type_mapping_and_uninferrable_context() + { + var contextFactory = await InitializeAsync( + onModelCreating: mb => mb.Entity( + b => b.Property(typeof(DateTime), "DateTime").HasColumnType("datetime"))); + + await using var context = contextFactory.CreateContext(); + + var dateTimes = new DateTime?[] { new DateTime(2020, 1, 1, 12, 30, 00), new DateTime(2020, 1, 2, 12, 30, 00), null }; + + var exception = await Assert.ThrowsAsync( + () => context.Set() + .Where( + m => dateTimes.Any(d => d == EF.Property(m, "DateTime") && d != null)) + .ToArrayAsync()); + Assert.Equal(RelationalStrings.ConflictingTypeMappingsInferredForColumn("value"), exception.Message); + } + [ConditionalFact] public virtual async Task Same_collection_with_conflicting_type_mappings_not_supported() {