Skip to content

Commit 8e430fb

Browse files
committed
Create correct JSON reader/writer for double nested value conversions (#32444)
1 parent 141740f commit 8e430fb

File tree

2 files changed

+91
-9
lines changed

2 files changed

+91
-9
lines changed

src/EFCore/Storage/CoreTypeMapping.cs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Diagnostics.CodeAnalysis;
55
using System.Runtime.CompilerServices;
66
using Microsoft.EntityFrameworkCore.Internal;
7+
using Microsoft.EntityFrameworkCore.Storage.Internal;
78
using Microsoft.EntityFrameworkCore.Storage.Json;
89

910
namespace Microsoft.EntityFrameworkCore.Storage;
@@ -130,15 +131,30 @@ public CoreTypeMappingParameters WithComposedConverter(
130131
ProviderValueComparer,
131132
ValueGeneratorFactory,
132133
elementMapping ?? ElementTypeMapping,
133-
jsonValueReaderWriter
134-
?? (converter == null || JsonValueReaderWriter == null
135-
? JsonValueReaderWriter
136-
: RuntimeFeature.IsDynamicCodeSupported
137-
? (JsonValueReaderWriter)Activator.CreateInstance(
138-
typeof(JsonConvertedValueReaderWriter<,>).MakeGenericType(
139-
converter.ModelClrType, JsonValueReaderWriter.ValueType),
140-
JsonValueReaderWriter, converter)!
141-
: throw new InvalidOperationException(CoreStrings.NativeAotNoCompiledModel)));
134+
jsonValueReaderWriter ?? CreateReaderWriter(converter, JsonValueReaderWriter));
135+
136+
static JsonValueReaderWriter? CreateReaderWriter(ValueConverter? converter, JsonValueReaderWriter? readerWriter)
137+
{
138+
if (converter == null || readerWriter == null)
139+
{
140+
return readerWriter;
141+
}
142+
143+
if (!RuntimeFeature.IsDynamicCodeSupported)
144+
{
145+
throw new InvalidOperationException(CoreStrings.NativeAotNoCompiledModel);
146+
}
147+
148+
if (readerWriter is IJsonConvertedValueReaderWriter convertedValueReaderWriter)
149+
{
150+
readerWriter = convertedValueReaderWriter.InnerReaderWriter;
151+
}
152+
153+
return (JsonValueReaderWriter)Activator.CreateInstance(
154+
typeof(JsonConvertedValueReaderWriter<,>).MakeGenericType(
155+
converter.ModelClrType, readerWriter.ValueType),
156+
readerWriter, converter)!;
157+
}
142158
}
143159
}
144160

test/EFCore.Specification.Tests/JsonTypesTestBase.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,6 +1667,72 @@ protected class NullableDddIdType
16671667
public DddId? DddId { get; set; }
16681668
}
16691669

1670+
[ConditionalTheory]
1671+
[InlineData(EnumProperty.FieldA, """{"Prop":"A"}""")]
1672+
[InlineData(EnumProperty.FieldB, """{"Prop":"B"}""")]
1673+
public virtual void Can_read_write_enum_char_converted_type_JSON_values(int value, string json)
1674+
=> Can_read_and_write_JSON_value<EnumCharType, EnumProperty>(
1675+
b => b.Entity<EnumCharType>().HasNoKey().Property(e => e.EnumProperty),
1676+
b => b.Properties<EnumProperty>().HaveConversion<EnumValueConverter<EnumProperty>>(),
1677+
nameof(EnumCharType.EnumProperty),
1678+
(EnumProperty)value,
1679+
json);
1680+
1681+
protected class EnumValueConverter<T>() : ValueConverter<T, char>(
1682+
p => p.ToChar(null), p => (T)Enum.Parse(typeof(T), Convert.ToInt32(p).ToString()))
1683+
where T : Enum, IConvertible;
1684+
1685+
protected class EnumCharType
1686+
{
1687+
public EnumProperty EnumProperty { get; set; }
1688+
}
1689+
1690+
protected enum EnumProperty
1691+
{
1692+
FieldA = 'A',
1693+
FieldB = 'B',
1694+
FieldC = 'C',
1695+
}
1696+
1697+
[ConditionalTheory]
1698+
[InlineData("127.0.0.1", """{"Prop":"127.0.0.1"}""")]
1699+
[InlineData("0.0.0.0", """{"Prop":"0.0.0.0"}""")]
1700+
[InlineData("255.255.255.255", """{"Prop":"255.255.255.255"}""")]
1701+
[InlineData("192.168.1.156", """{"Prop":"192.168.1.156"}""")]
1702+
[InlineData("::1", """{"Prop":"::1"}""")]
1703+
[InlineData("::", """{"Prop":"::"}""")]
1704+
[InlineData("2a00:23c7:c60f:4f01:ba43:6d5a:e648:7577", """{"Prop":"2a00:23c7:c60f:4f01:ba43:6d5a:e648:7577"}""")]
1705+
public virtual void Can_read_write_custom_converted_type_JSON_values(string value, string json)
1706+
=> Can_read_and_write_JSON_value<IpAddressType, IpAddress>(
1707+
b => b.Entity<IpAddressType>().HasNoKey().Property(e => e.Address),
1708+
b => b.Properties<IpAddress>().HaveConversion<IpAddressConverter>(),
1709+
nameof(IpAddressType.Address),
1710+
new(IPAddress.Parse(value)),
1711+
json);
1712+
1713+
protected class IpAddressConverter() : ValueConverter<IpAddress, IPAddress>(
1714+
v => v.Address,
1715+
v => new IpAddress(v));
1716+
1717+
protected class IpAddressType
1718+
{
1719+
public IpAddress? Address { get; set; }
1720+
}
1721+
1722+
protected class IpAddress(IPAddress address)
1723+
{
1724+
public IPAddress Address { get; } = address;
1725+
1726+
protected bool Equals(IpAddress other)
1727+
=> Address.Equals(other.Address);
1728+
1729+
public override bool Equals(object? obj)
1730+
=> !ReferenceEquals(null, obj) && (ReferenceEquals(this, obj) || obj.GetType() == GetType() && Equals((IpAddress)obj));
1731+
1732+
public override int GetHashCode()
1733+
=> Address.GetHashCode();
1734+
}
1735+
16701736
[ConditionalFact]
16711737
public virtual void Can_read_write_collection_of_sbyte_JSON_values()
16721738
=> Can_read_and_write_JSON_value<Int8CollectionType, List<sbyte>>(

0 commit comments

Comments
 (0)