diff --git a/src/EFCore/Metadata/Builders/PropertyBuilder.cs b/src/EFCore/Metadata/Builders/PropertyBuilder.cs
index 848a3f29809..594397e7fda 100644
--- a/src/EFCore/Metadata/Builders/PropertyBuilder.cs
+++ b/src/EFCore/Metadata/Builders/PropertyBuilder.cs
@@ -4,6 +4,7 @@
using System;
using System.ComponentModel;
using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
@@ -399,6 +400,46 @@ public virtual PropertyBuilder HasConversion([CanBeNull] ValueConverter converte
return this;
}
+ ///
+ /// Configures the property so that the property value is converted to the given type before
+ /// writing to the database and converted back when reading from the database.
+ ///
+ /// The comparer to use for values before conversion.
+ /// The type to convert to and from.
+ /// The same builder instance so that multiple configuration calls can be chained.
+ public virtual PropertyBuilder HasConversion([CanBeNull] ValueComparer valueComparer)
+ => HasConversion(typeof(TProvider), valueComparer);
+
+ ///
+ /// Configures the property so that the property value is converted to the given type before
+ /// writing to the database and converted back when reading from the database.
+ ///
+ /// The type to convert to and from.
+ /// The comparer to use for values before conversion.
+ /// The same builder instance so that multiple configuration calls can be chained.
+ public virtual PropertyBuilder HasConversion([CanBeNull] Type providerClrType, [CanBeNull] ValueComparer valueComparer)
+ {
+ Builder.HasConversion(providerClrType, ConfigurationSource.Explicit);
+ Builder.HasValueComparer(valueComparer, ConfigurationSource.Explicit);
+
+ return this;
+ }
+
+ ///
+ /// Configures the property so that the property value is converted to and from the database
+ /// using the given .
+ ///
+ /// The converter to use.
+ /// The comparer to use for values before conversion.
+ /// The same builder instance so that multiple configuration calls can be chained.
+ public virtual PropertyBuilder HasConversion([CanBeNull] ValueConverter converter, [CanBeNull] ValueComparer valueComparer)
+ {
+ Builder.HasConversion(converter, ConfigurationSource.Explicit);
+ Builder.HasValueComparer(valueComparer, ConfigurationSource.Explicit);
+
+ return this;
+ }
+
#region Hidden System.Object members
///
diff --git a/src/EFCore/Metadata/Builders/PropertyBuilder`.cs b/src/EFCore/Metadata/Builders/PropertyBuilder`.cs
index 6134bc9374c..573fdb61f66 100644
--- a/src/EFCore/Metadata/Builders/PropertyBuilder`.cs
+++ b/src/EFCore/Metadata/Builders/PropertyBuilder`.cs
@@ -4,6 +4,7 @@
using System;
using System.Linq.Expressions;
using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.EntityFrameworkCore.Utilities;
@@ -306,6 +307,72 @@ public virtual PropertyBuilder HasConversion([CanBeNull] V
public new virtual PropertyBuilder HasConversion([CanBeNull] ValueConverter converter)
=> (PropertyBuilder)base.HasConversion(converter);
+ ///
+ /// Configures the property so that the property value is converted to the given type before
+ /// writing to the database and converted back when reading from the database.
+ ///
+ /// The type to convert to and from.
+ /// The comparer to use for values before conversion.
+ /// The same builder instance so that multiple configuration calls can be chained.
+ public new virtual PropertyBuilder HasConversion([CanBeNull] ValueComparer valueComparer)
+ => (PropertyBuilder)base.HasConversion(valueComparer);
+
+ ///
+ /// Configures the property so that the property value is converted to the given type before
+ /// writing to the database and converted back when reading from the database.
+ ///
+ /// The type to convert to and from.
+ /// The comparer to use for values before conversion.
+ /// The same builder instance so that multiple configuration calls can be chained.
+ public new virtual PropertyBuilder HasConversion(
+ [CanBeNull] Type providerClrType,
+ [CanBeNull] ValueComparer valueComparer)
+ => (PropertyBuilder)base.HasConversion(providerClrType, valueComparer);
+
+ ///
+ /// Configures the property so that the property value is converted to and from the database
+ /// using the given conversion expressions.
+ ///
+ /// The store type generated by the conversions.
+ /// An expression to convert objects when writing data to the store.
+ /// An expression to convert objects when reading data from the store.
+ /// The comparer to use for values before conversion.
+ /// The same builder instance so that multiple configuration calls can be chained.
+ public virtual PropertyBuilder HasConversion(
+ [NotNull] Expression> convertToProviderExpression,
+ [NotNull] Expression> convertFromProviderExpression,
+ [CanBeNull] ValueComparer valueComparer)
+ => HasConversion(
+ new ValueConverter(
+ Check.NotNull(convertToProviderExpression, nameof(convertToProviderExpression)),
+ Check.NotNull(convertFromProviderExpression, nameof(convertFromProviderExpression))),
+ valueComparer);
+
+ ///
+ /// Configures the property so that the property value is converted to and from the database
+ /// using the given .
+ ///
+ /// The store type generated by the converter.
+ /// The converter to use.
+ /// The comparer to use for values before conversion.
+ /// The same builder instance so that multiple configuration calls can be chained.
+ public virtual PropertyBuilder HasConversion(
+ [CanBeNull] ValueConverter converter,
+ [CanBeNull] ValueComparer valueComparer)
+ => HasConversion((ValueConverter)converter, valueComparer);
+
+ ///
+ /// Configures the property so that the property value is converted to and from the database
+ /// using the given .
+ ///
+ /// The converter to use.
+ /// The comparer to use for values before conversion.
+ /// The same builder instance so that multiple configuration calls can be chained.
+ public new virtual PropertyBuilder HasConversion(
+ [CanBeNull] ValueConverter converter,
+ [CanBeNull] ValueComparer valueComparer)
+ => (PropertyBuilder)base.HasConversion(converter, valueComparer);
+
///
///
/// Sets the to use for this property.
diff --git a/test/EFCore.Specification.Tests/CustomConvertersTestBase.cs b/test/EFCore.Specification.Tests/CustomConvertersTestBase.cs
index a6281c93e1d..590964176fa 100644
--- a/test/EFCore.Specification.Tests/CustomConvertersTestBase.cs
+++ b/test/EFCore.Specification.Tests/CustomConvertersTestBase.cs
@@ -998,15 +998,20 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
modelBuilder.Entity(
b =>
{
- var property = b.Property(e => e.StringKeyDataTypeId)
- .HasConversion(v => "KeyValue=" + v, v => v.Substring(9)).Metadata;
-
- property.SetValueComparer(caseInsensitiveComparer);
+ b.Property(e => e.StringKeyDataTypeId)
+ .HasConversion(
+ v => "KeyValue=" + v,
+ v => v.Substring(9),
+ caseInsensitiveComparer);
});
modelBuilder.Entity(
b =>
{
+ var bytesComparer = new ValueComparer(
+ (v1, v2) => v1.SequenceEqual(v2),
+ v => v.GetHashCode());
+
b.Property(e => e.String3)
.HasConversion(
new ValueConverter(
@@ -1020,33 +1025,28 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
.HasConversion(
new ValueConverter(
v => v.Reverse().Concat(new byte[] { 4, 20 }).ToArray(),
- v => v.Reverse().Skip(2).ToArray()))
+ v => v.Reverse().Skip(2).ToArray()),
+ bytesComparer)
.HasMaxLength(7);
b.Property(e => e.ByteArray9000)
.HasConversion(
- BytesToStringConverter.DefaultInfo.Create())
+ BytesToStringConverter.DefaultInfo.Create(),
+ bytesComparer)
.HasMaxLength(LongStringLength * 2);
-
- var bytesComparer = new ValueComparer(
- (v1, v2) => v1.SequenceEqual(v2),
- v => v.GetHashCode());
-
- b.Property(e => e.ByteArray5).Metadata.SetValueComparer(bytesComparer);
- b.Property(e => e.ByteArray9000).Metadata.SetValueComparer(bytesComparer);
});
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Strings).HasConversion(v => string.Join(",", v), v => v.Split(new[] { ',' }).ToList());
- b.Property(e => e.Id).ValueGeneratedNever();
-
- var comparer = new ValueComparer>(
- (v1, v2) => v1.SequenceEqual(v2),
- v => v.GetHashCode());
+ b.Property(e => e.Strings).HasConversion(
+ v => string.Join(",", v),
+ v => v.Split(new[] { ',' }).ToList(),
+ new ValueComparer>(
+ (v1, v2) => v1.SequenceEqual(v2),
+ v => v.GetHashCode()));
- b.Property(e => e.Strings).Metadata.SetValueComparer(comparer);
+ b.Property(e => e.Id).ValueGeneratedNever();
});
modelBuilder.Entity(
@@ -1063,14 +1063,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
b.HasKey(c => c.CounterId);
b.Property(c => c.Discriminator).HasConversion(
d => StringToDictionarySerializer.Serialize(d),
- json => StringToDictionarySerializer.Deserialize(json));
-
- var comparer = new ValueComparer>(
- (v1, v2) => v1.SequenceEqual(v2),
- v => v.GetHashCode(),
- v => (IDictionary)new Dictionary(v));
-
- b.Property(e => e.Discriminator).Metadata.SetValueComparer(comparer);
+ json => StringToDictionarySerializer.Deserialize(json),
+ new ValueComparer>(
+ (v1, v2) => v1.SequenceEqual(v2),
+ v => v.GetHashCode(),
+ v => (IDictionary)new Dictionary(v)));
});
var urlConverter = new UrlSchemeRemover();
@@ -1127,8 +1124,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
{
b.Property(e => e.Tags).HasConversion(
c => string.Join(",", c),
- s => s.Split(',', StringSplitOptions.None).ToList()).Metadata
- .SetValueComparer(new ValueComparer>(favorStructuralComparisons: true));
+ s => s.Split(',', StringSplitOptions.None).ToList(),
+ new ValueComparer>(favorStructuralComparisons: true));
b.HasData(new CollectionScalar
{
@@ -1140,8 +1137,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Roles).HasConversion(new RolesToStringConveter()).Metadata
- .SetValueComparer(new ValueComparer>(favorStructuralComparisons: true));
+ b.Property(e => e.Roles).HasConversion(
+ new RolesToStringConveter(),
+ new ValueComparer>(favorStructuralComparisons: true));
b.HasData(new CollectionEnum
{