diff --git a/src/EFCore.Relational/Storage/DoubleTypeMapping.cs b/src/EFCore.Relational/Storage/DoubleTypeMapping.cs
index 36e89971154..a3d02de3d34 100644
--- a/src/EFCore.Relational/Storage/DoubleTypeMapping.cs
+++ b/src/EFCore.Relational/Storage/DoubleTypeMapping.cs
@@ -4,6 +4,7 @@
using System;
using System.Data;
using System.Globalization;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
using JetBrains.Annotations;
namespace Microsoft.EntityFrameworkCore.Storage
@@ -27,7 +28,10 @@ public class DoubleTypeMapping : RelationalTypeMapping
public DoubleTypeMapping(
[NotNull] string storeType,
DbType? dbType = null)
- : base(storeType, typeof(double), dbType)
+ : base(
+ new RelationalTypeMappingParameters(
+ new CoreTypeMappingParameters(typeof(double), comparer: new DoubleValueComparer()),
+ storeType, StoreTypePostfix.None, dbType, unicode: false, size: null, fixedLength: false, precision: null, scale: null))
{
}
diff --git a/src/EFCore.Relational/Storage/FloatTypeMapping.cs b/src/EFCore.Relational/Storage/FloatTypeMapping.cs
index 92833456ba5..4a0c83df974 100644
--- a/src/EFCore.Relational/Storage/FloatTypeMapping.cs
+++ b/src/EFCore.Relational/Storage/FloatTypeMapping.cs
@@ -5,6 +5,7 @@
using System.Data;
using System.Globalization;
using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
namespace Microsoft.EntityFrameworkCore.Storage
{
@@ -27,7 +28,10 @@ public class FloatTypeMapping : RelationalTypeMapping
public FloatTypeMapping(
[NotNull] string storeType,
DbType? dbType = null)
- : base(storeType, typeof(float), dbType)
+ : base(
+ new RelationalTypeMappingParameters(
+ new CoreTypeMappingParameters(typeof(float), comparer: new FloatValueComparer()),
+ storeType, StoreTypePostfix.None, dbType, unicode: false, size: null, fixedLength: false, precision: null, scale: null))
{
}
diff --git a/src/EFCore/ChangeTracking/ArrayStructuralComparer.cs b/src/EFCore/ChangeTracking/ArrayStructuralComparer.cs
index 3f5484e92e3..a3937a904d3 100644
--- a/src/EFCore/ChangeTracking/ArrayStructuralComparer.cs
+++ b/src/EFCore/ChangeTracking/ArrayStructuralComparer.cs
@@ -7,8 +7,8 @@ namespace Microsoft.EntityFrameworkCore.ChangeTracking
{
///
///
- /// Specifies value snapshotting and comparison for arrays where each element is compared
- /// a new array is constructed when snapshotting.
+ /// Specifies value comparison for arrays where each element pair is compared.
+ /// A new array is constructed when snapshotting.
///
///
/// The array element type.
diff --git a/src/EFCore/ChangeTracking/DoubleValueComparer.cs b/src/EFCore/ChangeTracking/DoubleValueComparer.cs
new file mode 100644
index 00000000000..3c1d630eea6
--- /dev/null
+++ b/src/EFCore/ChangeTracking/DoubleValueComparer.cs
@@ -0,0 +1,25 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Linq.Expressions;
+using JetBrains.Annotations;
+
+namespace Microsoft.EntityFrameworkCore.ChangeTracking
+{
+ ///
+ /// Defines value comparison for which correctly takes
+ /// into account.
+ ///
+ public class DoubleValueComparer : ValueComparer
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public DoubleValueComparer() : base(
+ (x, y) => double.IsNaN(x) ? double.IsNaN(y) : x.Equals(y),
+ d => d.GetHashCode())
+ {
+ }
+ }
+}
diff --git a/src/EFCore/ChangeTracking/FloatValueComparer.cs b/src/EFCore/ChangeTracking/FloatValueComparer.cs
new file mode 100644
index 00000000000..89fb828110b
--- /dev/null
+++ b/src/EFCore/ChangeTracking/FloatValueComparer.cs
@@ -0,0 +1,25 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Linq.Expressions;
+using JetBrains.Annotations;
+
+namespace Microsoft.EntityFrameworkCore.ChangeTracking
+{
+ ///
+ /// Defines value comparison for which correctly takes
+ /// into account.
+ ///
+ public class FloatValueComparer : ValueComparer
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public FloatValueComparer() : base(
+ (x, y) => float.IsNaN(x) ? float.IsNaN(y) : x.Equals(y),
+ d => d.GetHashCode())
+ {
+ }
+ }
+}
diff --git a/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs b/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs
index 7ba4084749e..e1fe8b92e5e 100644
--- a/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs
+++ b/test/EFCore.Relational.Tests/Storage/RelationalTypeMappingTest.cs
@@ -529,6 +529,26 @@ public virtual void UShort_literal_generated_correctly()
Test_GenerateSqlLiteral_helper(typeMapping, ushort.MaxValue, "65535");
}
+ [ConditionalFact]
+ public virtual void Double_value_comparer_handles_NaN()
+ {
+ var typeMapping = new DoubleTypeMapping("double precision", DbType.Double);
+
+ Assert.True(typeMapping.Comparer.Equals(3.0, 3.0));
+ Assert.True(typeMapping.Comparer.Equals(double.NaN, double.NaN));
+ Assert.False(typeMapping.Comparer.Equals(3.0, double.NaN));
+ }
+
+ [ConditionalFact]
+ public virtual void Float_value_comparer_handles_NaN()
+ {
+ var typeMapping = new FloatTypeMapping("float", DbType.Single);
+
+ Assert.True(typeMapping.Comparer.Equals(3.0f, 3.0f));
+ Assert.True(typeMapping.Comparer.Equals(float.NaN, float.NaN));
+ Assert.False(typeMapping.Comparer.Equals(3.0f, float.NaN));
+ }
+
[ConditionalFact]
public virtual void Primary_key_type_mapping_is_picked_up_by_FK_without_going_through_store_type()
{