diff --git a/src/EFCore/EFCore.baseline.json b/src/EFCore/EFCore.baseline.json index 7c9812b71e2..7758e38cca6 100644 --- a/src/EFCore/EFCore.baseline.json +++ b/src/EFCore/EFCore.baseline.json @@ -17294,7 +17294,7 @@ "Member": "abstract object FromJson(ref Microsoft.EntityFrameworkCore.Storage.Json.Utf8JsonReaderManager manager, object? existingObject = null);" }, { - "Member": "object FromJsonString(string json, object? existingObject = null);" + "Member": "object? FromJsonString(string json, object? existingObject = null);" }, { "Member": "abstract void ToJson(System.Text.Json.Utf8JsonWriter writer, object? value);" diff --git a/src/EFCore/Storage/Json/JsonValueReaderWriter.cs b/src/EFCore/Storage/Json/JsonValueReaderWriter.cs index 94daf881dcb..c70814cb8cd 100644 --- a/src/EFCore/Storage/Json/JsonValueReaderWriter.cs +++ b/src/EFCore/Storage/Json/JsonValueReaderWriter.cs @@ -70,7 +70,7 @@ internal JsonValueReaderWriter() /// The JSON to parse. /// Can be used to update an existing object, rather than create a new one. /// The read value. - public object FromJsonString(string json, object? existingObject = null) + public object? FromJsonString(string json, object? existingObject = null) { if (string.IsNullOrWhiteSpace(json)) { @@ -79,7 +79,9 @@ public object FromJsonString(string json, object? existingObject = null) var readerManager = new Utf8JsonReaderManager(new JsonReaderData(Encoding.UTF8.GetBytes(json)), null); readerManager.MoveNext(); - return FromJson(ref readerManager, existingObject); + return readerManager.CurrentReader.TokenType == JsonTokenType.Null + ? null + : FromJson(ref readerManager, existingObject); } /// diff --git a/test/EFCore.Specification.Tests/JsonTypesTestBase.cs b/test/EFCore.Specification.Tests/JsonTypesTestBase.cs index c50aeef9b48..a77eb8527fb 100644 --- a/test/EFCore.Specification.Tests/JsonTypesTestBase.cs +++ b/test/EFCore.Specification.Tests/JsonTypesTestBase.cs @@ -2623,6 +2623,45 @@ protected class NullableEnumU64CollectionType public IList EnumU64 { get; set; } = null!; } + [Fact] + public virtual Task Can_read_write_null_value_of_collection_of_string_JSON_values() + => Can_read_and_write_JSON_value?>( + nameof(NullStringCollectionType.String), + null, + """{"Prop":null}""", + mappedCollection: true); + + protected class NullStringCollectionType + { + public List? String { get; set; } + } + + [Fact] + public virtual Task Can_read_write_null_value_of_collection_of_int_JSON_values() + => Can_read_and_write_JSON_value?>( + nameof(NullIntCollectionType.Int32), + null, + """{"Prop":null}""", + mappedCollection: true); + + protected class NullIntCollectionType + { + public List? Int32 { get; set; } + } + + [Fact] + public virtual Task Can_read_write_null_value_of_collection_of_nullable_int_JSON_values() + => Can_read_and_write_JSON_value?>( + nameof(NullNullableIntCollectionType.Int32), + null, + """{"Prop":null}""", + mappedCollection: true); + + protected class NullNullableIntCollectionType + { + public List? Int32 { get; set; } + } + [Fact] public virtual Task Can_read_write_collection_of_sbyte_values_with_converter_as_JSON_string() => Can_read_and_write_JSON_property_value( @@ -3671,16 +3710,18 @@ protected virtual Task Can_read_and_write_JSON_value( using var writer = new Utf8JsonWriter(stream); var jsonReaderWriter = property.GetJsonValueReaderWriter() - ?? property.GetTypeMapping().JsonValueReaderWriter!; + ?? property.GetTypeMapping().JsonValueReaderWriter; - var toString = value == null ? null : jsonReaderWriter.ToJsonString(value); - var fromString = toString == null ? null : jsonReaderWriter.FromJsonString(toString, existingObject); + var toString = value == null ? null : jsonReaderWriter!.ToJsonString(value); + var fromString = value == null + ? jsonReaderWriter?.FromJsonString("null") + : jsonReaderWriter!.FromJsonString(toString!, existingObject); Assert.Equal(value, fromString); - var actual = ToJsonPropertyString(jsonReaderWriter, value); + var actual = ToJsonPropertyString(jsonReaderWriter!, value); Assert.Equal(json, actual); - var fromJson = FromJsonPropertyString(jsonReaderWriter, actual, existingObject); + var fromJson = FromJsonPropertyString(jsonReaderWriter!, actual, existingObject); if (existingObject != null) { Assert.Same(fromJson, existingObject); @@ -3717,15 +3758,18 @@ protected virtual Task Can_read_and_write_JSON_value( Assert.Equal(elementNullable, element.IsNullable); - var comparer = element.GetValueComparer()!; - var elementReaderWriter = element.GetJsonValueReaderWriter()!; - foreach (var item in (IEnumerable)value!) + if (value != null) { - Assert.True(comparer.Equals(item, comparer.Snapshot(item))); - Assert.True( - comparer.Equals( - item, FromJsonPropertyString( - elementReaderWriter, ToJsonPropertyString(elementReaderWriter, item)))); + var comparer = element.GetValueComparer()!; + var elementReaderWriter = element.GetJsonValueReaderWriter()!; + foreach (var item in (IEnumerable)value) + { + Assert.True(comparer.Equals(item, comparer.Snapshot(item))); + Assert.True( + comparer.Equals( + item, FromJsonPropertyString( + elementReaderWriter, ToJsonPropertyString(elementReaderWriter, item)))); + } } AssertElementFacets(element, facets);