Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/EFCore/Properties/CoreStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/EFCore/Properties/CoreStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,9 @@
<data name="EmptyComplexType" xml:space="preserve">
<value>Complex type '{complexType}' has no properties defines. Configure at least one property or don't include this type in the model.</value>
</data>
<data name="EmptyJsonString" xml:space="preserve">
<value>The empty string is not valid JSON.</value>
</data>
<data name="EntityEqualityOnCompositeKeyEntitySubqueryNotSupported" xml:space="preserve">
<value>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.</value>
</data>
Expand Down
9 changes: 9 additions & 0 deletions src/EFCore/Storage/Json/JsonValueReaderWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ namespace Microsoft.EntityFrameworkCore.Storage.Json;
/// </remarks>
public abstract class JsonValueReaderWriter
{
private static readonly bool UseOldBehavior32896 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32896", out var enabled32896) && enabled32896;

/// <summary>
/// Ensures the external types extend from the generic <see cref="JsonValueReaderWriter{TValue}" />
/// </summary>
Expand Down Expand Up @@ -63,6 +66,12 @@ internal JsonValueReaderWriter()
/// <returns>The read value.</returns>
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<InvalidOperationException>(
async () =>
{
if (async)
{
await set.FirstAsync();
}
else
{
set.First();
}
});

Assert.Equal(CoreStrings.EmptyJsonString, message.Message);
}

public class SimpleContext(SqliteConnection connection) : DbContext
{
public DbSet<SimpleEntity> SimpleEntities => Set<SimpleEntity>();

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlite(connection);
}

public record SimpleEntity(int Id, IEnumerable<string> List);

[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());
Expand Down