diff --git a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlCidrLegacyTypeMapping.cs b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlCidrLegacyTypeMapping.cs
new file mode 100644
index 000000000..683cd54aa
--- /dev/null
+++ b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlCidrLegacyTypeMapping.cs
@@ -0,0 +1,125 @@
+using System.Net;
+using System.Text.Json;
+using Microsoft.EntityFrameworkCore.Storage.Json;
+
+namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
+
+///
+/// The type mapping for the PostgreSQL cidr type.
+///
+///
+/// See: https://www.postgresql.org/docs/current/static/datatype-net-types.html#DATATYPE-CIDR
+///
+public class NpgsqlLegacyCidrTypeMapping : NpgsqlTypeMapping
+{
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public static NpgsqlLegacyCidrTypeMapping Default { get; } = new();
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public NpgsqlLegacyCidrTypeMapping()
+ : base("cidr", typeof(NpgsqlCidr), NpgsqlDbType.Cidr, JsonCidrLegacyReaderWriter.Instance)
+ {
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ protected NpgsqlLegacyCidrTypeMapping(RelationalTypeMappingParameters parameters)
+ : base(parameters, NpgsqlDbType.Cidr)
+ {
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
+ => new NpgsqlLegacyCidrTypeMapping(parameters);
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ protected override string GenerateNonNullSqlLiteral(object value)
+ {
+ var cidr = (NpgsqlCidr)value;
+ return $"CIDR '{cidr.Address}/{cidr.Netmask}'";
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public override Expression GenerateCodeLiteral(object value)
+ {
+ var cidr = (NpgsqlCidr)value;
+ return Expression.New(
+ NpgsqlCidrConstructor,
+ Expression.Call(ParseMethod, Expression.Constant(cidr.Address.ToString())),
+ Expression.Constant(cidr.Netmask));
+ }
+
+ private static readonly MethodInfo ParseMethod = typeof(IPAddress).GetMethod("Parse", [typeof(string)])!;
+
+ private static readonly ConstructorInfo NpgsqlCidrConstructor =
+ typeof(NpgsqlCidr).GetConstructor([typeof(IPAddress), typeof(byte)])!;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public sealed class JsonCidrLegacyReaderWriter : JsonValueReaderWriter
+ {
+ private static readonly PropertyInfo InstanceProperty = typeof(JsonCidrLegacyReaderWriter).GetProperty(nameof(Instance))!;
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public static JsonCidrLegacyReaderWriter Instance { get; } = new();
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public override NpgsqlCidr FromJsonTyped(ref Utf8JsonReaderManager manager, object? existingObject = null)
+ => new(manager.CurrentReader.GetString()!);
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public override void ToJsonTyped(Utf8JsonWriter writer, NpgsqlCidr value)
+ => writer.WriteStringValue(value.ToString());
+
+ ///
+ public override Expression ConstructorExpression => Expression.Property(null, InstanceProperty);
+ }
+}
diff --git a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlCidrTypeMapping.cs b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlCidrTypeMapping.cs
index 7a943d887..86c4c6ef2 100644
--- a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlCidrTypeMapping.cs
+++ b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlCidrTypeMapping.cs
@@ -27,7 +27,7 @@ public class NpgsqlCidrTypeMapping : NpgsqlTypeMapping
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public NpgsqlCidrTypeMapping()
- : base("cidr", typeof(NpgsqlCidr), NpgsqlDbType.Cidr, JsonCidrReaderWriter.Instance)
+ : base("cidr", typeof(IPNetwork), NpgsqlDbType.Cidr, JsonCidrReaderWriter.Instance)
{
}
@@ -59,8 +59,8 @@ protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters p
///
protected override string GenerateNonNullSqlLiteral(object value)
{
- var cidr = (NpgsqlCidr)value;
- return $"CIDR '{cidr.Address}/{cidr.Netmask}'";
+ var ipNetwork = (IPNetwork)value;
+ return $"CIDR '{ipNetwork.BaseAddress}/{ipNetwork.PrefixLength}'";
}
///
@@ -71,17 +71,17 @@ protected override string GenerateNonNullSqlLiteral(object value)
///
public override Expression GenerateCodeLiteral(object value)
{
- var cidr = (NpgsqlCidr)value;
+ var cidr = (IPNetwork)value;
return Expression.New(
NpgsqlCidrConstructor,
- Expression.Call(ParseMethod, Expression.Constant(cidr.Address.ToString())),
- Expression.Constant(cidr.Netmask));
+ Expression.Call(ParseMethod, Expression.Constant(cidr.BaseAddress.ToString())),
+ Expression.Constant(cidr.PrefixLength));
}
private static readonly MethodInfo ParseMethod = typeof(IPAddress).GetMethod("Parse", [typeof(string)])!;
private static readonly ConstructorInfo NpgsqlCidrConstructor =
- typeof(NpgsqlCidr).GetConstructor([typeof(IPAddress), typeof(byte)])!;
+ typeof(IPNetwork).GetConstructor([typeof(IPAddress), typeof(int)])!;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -89,7 +89,7 @@ public override Expression GenerateCodeLiteral(object value)
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public sealed class JsonCidrReaderWriter : JsonValueReaderWriter
+ public sealed class JsonCidrReaderWriter : JsonValueReaderWriter
{
private static readonly PropertyInfo InstanceProperty = typeof(JsonCidrReaderWriter).GetProperty(nameof(Instance))!;
@@ -107,8 +107,8 @@ public sealed class JsonCidrReaderWriter : JsonValueReaderWriter
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public override NpgsqlCidr FromJsonTyped(ref Utf8JsonReaderManager manager, object? existingObject = null)
- => new(manager.CurrentReader.GetString()!);
+ public override IPNetwork FromJsonTyped(ref Utf8JsonReaderManager manager, object? existingObject = null)
+ => IPNetwork.Parse(manager.CurrentReader.GetString()!);
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -116,8 +116,8 @@ public override NpgsqlCidr FromJsonTyped(ref Utf8JsonReaderManager manager, obje
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public override void ToJsonTyped(Utf8JsonWriter writer, NpgsqlCidr value)
- => writer.WriteStringValue(value.ToString());
+ public override void ToJsonTyped(Utf8JsonWriter writer, IPNetwork ipNetwork)
+ => writer.WriteStringValue(ipNetwork.ToString());
///
public override Expression ConstructorExpression => Expression.Property(null, InstanceProperty);
diff --git a/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs b/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs
index d1b922231..a259c2020 100644
--- a/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs
+++ b/src/EFCore.PG/Storage/Internal/NpgsqlTypeMappingSource.cs
@@ -114,7 +114,8 @@ static NpgsqlTypeMappingSource()
private readonly NpgsqlMacaddr8TypeMapping _macaddr8 = NpgsqlMacaddr8TypeMapping.Default;
private readonly NpgsqlInetTypeMapping _inetAsIPAddress = NpgsqlInetTypeMapping.Default;
private readonly NpgsqlInetTypeMapping _inetAsNpgsqlInet = new(typeof(NpgsqlInet));
- private readonly NpgsqlCidrTypeMapping _cidr = NpgsqlCidrTypeMapping.Default;
+ private readonly NpgsqlCidrTypeMapping _cidrAsIPNetwork = NpgsqlCidrTypeMapping.Default;
+ private readonly NpgsqlLegacyCidrTypeMapping _cidrAsNpgsqlCidr = NpgsqlLegacyCidrTypeMapping.Default;
// Built-in geometric types
private readonly NpgsqlPointTypeMapping _point = NpgsqlPointTypeMapping.Default;
@@ -257,7 +258,7 @@ public NpgsqlTypeMappingSource(
{ "macaddr", [_macaddr] },
{ "macaddr8", [_macaddr8] },
{ "inet", [_inetAsIPAddress, _inetAsNpgsqlInet] },
- { "cidr", [_cidr] },
+ { "cidr", [_cidrAsIPNetwork, _cidrAsNpgsqlCidr] },
{ "point", [_point] },
{ "box", [_box] },
{ "line", [_line] },
@@ -320,7 +321,8 @@ public NpgsqlTypeMappingSource(
{ typeof(PhysicalAddress), _macaddr },
{ typeof(IPAddress), _inetAsIPAddress },
{ typeof(NpgsqlInet), _inetAsNpgsqlInet },
- { typeof(NpgsqlCidr), _cidr },
+ { typeof(IPNetwork), _cidrAsIPNetwork },
+ { typeof(NpgsqlCidr), _cidrAsNpgsqlCidr },
{ typeof(BitArray), _varbit },
{ typeof(ImmutableDictionary), _immutableHstore },
{ typeof(Dictionary), _hstore },
diff --git a/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingSourceTest.cs b/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingSourceTest.cs
index e95bbdd19..622405946 100644
--- a/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingSourceTest.cs
+++ b/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingSourceTest.cs
@@ -1,3 +1,5 @@
+using System.Net;
+using System.Net.NetworkInformation;
using Microsoft.EntityFrameworkCore.Storage.Json;
using NetTopologySuite.Geometries;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
@@ -41,6 +43,7 @@ public class NpgsqlTypeMappingSourceTest
[InlineData("geometry(POLYGONM)", typeof(Polygon), null, null, null, false)]
[InlineData("xid", typeof(uint), null, null, null, false)]
[InlineData("xid8", typeof(ulong), null, null, null, false)]
+ [InlineData("cidr", typeof(IPNetwork), null, null, null, false)]
public void By_StoreType(string typeName, Type type, int? size, int? precision, int? scale, bool fixedLength)
{
var mapping = CreateTypeMappingSource().FindMapping(typeName);
@@ -114,6 +117,10 @@ public void Timestamp_without_time_zone_Array_5()
[InlineData(typeof(List>), "int4multirange")]
[InlineData(typeof(Geometry), "geometry")]
[InlineData(typeof(Point), "geometry")]
+ [InlineData(typeof(IPAddress), "inet")]
+ [InlineData(typeof(IPNetwork), "cidr")]
+ [InlineData(typeof(NpgsqlCidr), "cidr")] // legacy
+ [InlineData(typeof(PhysicalAddress), "macaddr")]
public void By_ClrType(Type clrType, string expectedStoreType)
{
var mapping = CreateTypeMappingSource().FindMapping(clrType);
diff --git a/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingTest.cs b/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingTest.cs
index ea8f3663a..4db128a9c 100644
--- a/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingTest.cs
+++ b/test/EFCore.PG.Tests/Storage/NpgsqlTypeMappingTest.cs
@@ -282,10 +282,20 @@ public void GenerateCodeLiteral_returns_inet_literal()
[Fact]
public void GenerateSqlLiteral_returns_cidr_literal()
+ => Assert.Equal("CIDR '192.168.1.0/24'", GetMapping("cidr").GenerateSqlLiteral(new IPNetwork(IPAddress.Parse("192.168.1.0"), 24)));
+
+ [Fact]
+ public void GenerateSqlLiteral_returns_legacy_cidr_literal()
=> Assert.Equal("CIDR '192.168.1.0/24'", GetMapping("cidr").GenerateSqlLiteral(new NpgsqlCidr(IPAddress.Parse("192.168.1.0"), 24)));
[Fact]
public void GenerateCodeLiteral_returns_cidr_literal()
+ => Assert.Equal(
+ """new System.Net.IPNetwork(System.Net.IPAddress.Parse("192.168.1.0"), 24)""",
+ CodeLiteral(new IPNetwork(IPAddress.Parse("192.168.1.0"), 24)));
+
+ [Fact]
+ public void GenerateCodeLiteral_returns_legacy_cidr_literal()
=> Assert.Equal(
"""new NpgsqlTypes.NpgsqlCidr(System.Net.IPAddress.Parse("192.168.1.0"), (byte)24)""",
CodeLiteral(new NpgsqlCidr(IPAddress.Parse("192.168.1.0"), 24)));