diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs
index fd7a93208b0..8c9cd8e6df6 100644
--- a/src/EFCore/Properties/CoreStrings.Designer.cs
+++ b/src/EFCore/Properties/CoreStrings.Designer.cs
@@ -993,6 +993,12 @@ public static string EmptyComplexType(object? complexType)
GetString("EmptyComplexType", nameof(complexType)),
complexType);
+ ///
+ /// The empty string is not valid JSON.
+ ///
+ public static string EmptyJsonString
+ => GetString("EmptyJsonString");
+
///
/// Cannot translate '{comparisonOperator}' on a subquery expression of entity type '{entityType}' because it has a composite primary key. See https://go.microsoft.com/fwlink/?linkid=2141942 for information on how to rewrite your query.
///
diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx
index 45b45251ed8..e3f7f5d18d2 100644
--- a/src/EFCore/Properties/CoreStrings.resx
+++ b/src/EFCore/Properties/CoreStrings.resx
@@ -486,6 +486,9 @@
Complex type '{complexType}' has no properties defines. Configure at least one property or don't include this type in the model.
+
+ The empty string is not valid JSON.
+
Cannot translate '{comparisonOperator}' on a subquery expression of entity type '{entityType}' because it has a composite primary key. See https://go.microsoft.com/fwlink/?linkid=2141942 for information on how to rewrite your query.
diff --git a/src/EFCore/Storage/Json/JsonValueReaderWriter.cs b/src/EFCore/Storage/Json/JsonValueReaderWriter.cs
index 92e2c2f3021..2a085ebbfed 100644
--- a/src/EFCore/Storage/Json/JsonValueReaderWriter.cs
+++ b/src/EFCore/Storage/Json/JsonValueReaderWriter.cs
@@ -14,6 +14,9 @@ namespace Microsoft.EntityFrameworkCore.Storage.Json;
///
public abstract class JsonValueReaderWriter
{
+ private static readonly bool UseOldBehavior32896 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32896", out var enabled32896) && enabled32896;
+
///
/// Ensures the external types extend from the generic
///
@@ -63,6 +66,12 @@ internal JsonValueReaderWriter()
/// The read value.
public object FromJsonString(string json, object? existingObject = null)
{
+ if (!UseOldBehavior32896
+ && string.IsNullOrWhiteSpace(json))
+ {
+ throw new InvalidOperationException(CoreStrings.EmptyJsonString);
+ }
+
var readerManager = new Utf8JsonReaderManager(new JsonReaderData(Encoding.UTF8.GetBytes(json)), null);
return FromJson(ref readerManager, existingObject);
}
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs
index 98e6272c451..12ba1fc3033 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/PrimitiveCollectionsQuerySqliteTest.cs
@@ -1317,6 +1317,48 @@ FROM json_each(@__strings_0) AS "s"
""");
}
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)] // Issue #32896
+ public async Task Empty_string_used_for_primitive_collection_throws(bool async)
+ {
+ await using var connection = new SqliteConnection("DataSource=:memory:");
+ await connection.OpenAsync();
+
+ await using var context = new SimpleContext(connection);
+ await context.Database.EnsureDeletedAsync();
+ await context.Database.EnsureCreatedAsync();
+
+ await context.Database.ExecuteSqlRawAsync("INSERT INTO SimpleEntities (List) VALUES ('');");
+
+ var set = context.SimpleEntities;
+
+ var message = await Assert.ThrowsAsync(
+ async () =>
+ {
+ if (async)
+ {
+ await set.FirstAsync();
+ }
+ else
+ {
+ set.First();
+ }
+ });
+
+ Assert.Equal(CoreStrings.EmptyJsonString, message.Message);
+ }
+
+ public class SimpleContext(SqliteConnection connection) : DbContext
+ {
+ public DbSet SimpleEntities => Set();
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ => optionsBuilder.UseSqlite(connection);
+ }
+
+ public record SimpleEntity(int Id, IEnumerable List);
+
[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());