Skip to content

Commit

Permalink
Add value converters
Browse files Browse the repository at this point in the history
  • Loading branch information
roji committed Jan 23, 2023
1 parent 751141c commit 482b15c
Show file tree
Hide file tree
Showing 18 changed files with 684 additions and 11 deletions.
2 changes: 2 additions & 0 deletions src/EFCore/ChangeTracking/ValueComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,10 @@ public static ValueComparer CreateDefault(
|| nonNullableType == typeof(bool)
|| nonNullableType == typeof(string)
|| nonNullableType == typeof(DateTime)
|| nonNullableType == typeof(DateOnly)
|| nonNullableType == typeof(Guid)
|| nonNullableType == typeof(TimeSpan)
|| nonNullableType == typeof(TimeOnly)
? typeof(DefaultValueComparer<>)
: typeof(ValueComparer<>);

Expand Down
50 changes: 50 additions & 0 deletions src/EFCore/Storage/ValueConversion/DateOnlyToStringConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;

namespace Microsoft.EntityFrameworkCore.Storage.ValueConversion;

/// <summary>
/// Converts <see cref="DateOnly" /> to and from strings.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
public class DateOnlyToStringConverter : StringDateOnlyConverter<DateOnly, string>
{
/// <summary>
/// Creates a new instance of this converter.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
public DateOnlyToStringConverter()
: this(null)
{
}

/// <summary>
/// Creates a new instance of this converter.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
/// <param name="mappingHints">
/// Hints that can be used by the <see cref="ITypeMappingSource" /> to create data types with appropriate
/// facets for the converted data.
/// </param>
public DateOnlyToStringConverter(ConverterMappingHints? mappingHints)
: base(
ToString(),
ToDateOnly(),
DefaultHints.With(mappingHints))
{
}

/// <summary>
/// A <see cref="ValueConverterInfo" /> for the default use of this converter.
/// </summary>
public static ValueConverterInfo DefaultInfo { get; }
= new(typeof(DateOnly), typeof(string), i => new DateOnlyToStringConverter(i.MappingHints), DefaultHints);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Globalization;

namespace Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;

/// <summary>
/// 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.
/// </summary>
public class StringDateOnlyConverter<TModel, TProvider> : ValueConverter<TModel, TProvider>
{
/// <summary>
/// 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.
/// </summary>
// ReSharper disable once StaticMemberInGenericType
protected static readonly ConverterMappingHints DefaultHints = new(size: 10);

/// <summary>
/// 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.
/// </summary>
public StringDateOnlyConverter(
Expression<Func<TModel, TProvider>> convertToProviderExpression,
Expression<Func<TProvider, TModel>> convertFromProviderExpression,
ConverterMappingHints? mappingHints = null)
: base(convertToProviderExpression, convertFromProviderExpression, mappingHints)
{
}

/// <summary>
/// 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.
/// </summary>
protected static new Expression<Func<DateOnly, string>> ToString()
=> v => v.ToString(@"yyyy\-MM\-dd");

/// <summary>
/// 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.
/// </summary>
protected static Expression<Func<string, DateOnly>> ToDateOnly()
=> v => DateOnly.Parse(v, CultureInfo.InvariantCulture, DateTimeStyles.None);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Globalization;

namespace Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;

/// <summary>
/// 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.
/// </summary>
public class StringTimeOnlyConverter<TModel, TProvider> : ValueConverter<TModel, TProvider>
{
/// <summary>
/// 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.
/// </summary>
// ReSharper disable once StaticMemberInGenericType
protected static readonly ConverterMappingHints DefaultHints = new(size: 48);

/// <summary>
/// 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.
/// </summary>
public StringTimeOnlyConverter(
Expression<Func<TModel, TProvider>> convertToProviderExpression,
Expression<Func<TProvider, TModel>> convertFromProviderExpression,
ConverterMappingHints? mappingHints = null)
: base(convertToProviderExpression, convertFromProviderExpression, mappingHints)
{
}

/// <summary>
/// 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.
/// </summary>
protected static new Expression<Func<TimeOnly, string>> ToString()
=> v => v.Ticks % 10000000 == 0
? string.Format(CultureInfo.InvariantCulture, @"{0:HH\:mm\:ss}", v)
: v.ToString("o");

/// <summary>
/// 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.
/// </summary>
protected static Expression<Func<string, TimeOnly>> ToTimeOnly()
=> v => TimeOnly.Parse(v, CultureInfo.InvariantCulture, DateTimeStyles.None);
}
50 changes: 50 additions & 0 deletions src/EFCore/Storage/ValueConversion/StringToDateOnlyConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;

namespace Microsoft.EntityFrameworkCore.Storage.ValueConversion;

/// <summary>
/// Converts strings to and from <see cref="DateOnly" /> values.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
public class StringToDateOnlyConverter : StringDateOnlyConverter<string, DateOnly>
{
/// <summary>
/// Creates a new instance of this converter.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
public StringToDateOnlyConverter()
: this(null)
{
}

/// <summary>
/// Creates a new instance of this converter.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
/// <param name="mappingHints">
/// Hints that can be used by the <see cref="ITypeMappingSource" /> to create data types with appropriate
/// facets for the converted data.
/// </param>
public StringToDateOnlyConverter(ConverterMappingHints? mappingHints)
: base(
ToDateOnly(),
ToString(),
DefaultHints.With(mappingHints))
{
}

/// <summary>
/// A <see cref="ValueConverterInfo" /> for the default use of this converter.
/// </summary>
public static ValueConverterInfo DefaultInfo { get; }
= new(typeof(string), typeof(DateOnly), i => new StringToDateTimeConverter(i.MappingHints), DefaultHints);
}
50 changes: 50 additions & 0 deletions src/EFCore/Storage/ValueConversion/StringToTimeOnlyConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;

namespace Microsoft.EntityFrameworkCore.Storage.ValueConversion;

/// <summary>
/// Converts strings to and from <see cref="TimeOnly" /> values.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
public class StringToTimeOnlyConverter : StringTimeOnlyConverter<string, TimeOnly>
{
/// <summary>
/// Creates a new instance of this converter.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
public StringToTimeOnlyConverter()
: this(null)
{
}

/// <summary>
/// Creates a new instance of this converter.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
/// <param name="mappingHints">
/// Hints that can be used by the <see cref="ITypeMappingSource" /> to create data types with appropriate
/// facets for the converted data.
/// </param>
public StringToTimeOnlyConverter(ConverterMappingHints? mappingHints)
: base(
ToTimeOnly(),
ToString(),
DefaultHints.With(mappingHints))
{
}

/// <summary>
/// A <see cref="ValueConverterInfo" /> for the default use of this converter.
/// </summary>
public static ValueConverterInfo DefaultInfo { get; }
= new(typeof(string), typeof(TimeOnly), i => new StringToTimeOnlyConverter(i.MappingHints), DefaultHints);
}
50 changes: 50 additions & 0 deletions src/EFCore/Storage/ValueConversion/TimeOnlyToStringConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;

namespace Microsoft.EntityFrameworkCore.Storage.ValueConversion;

/// <summary>
/// Converts <see cref="TimeOnly" /> to and from strings.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
public class TimeOnlyToStringConverter : StringTimeOnlyConverter<TimeOnly, string>
{
/// <summary>
/// Creates a new instance of this converter.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
public TimeOnlyToStringConverter()
: this(null)
{
}

/// <summary>
/// Creates a new instance of this converter.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
/// <param name="mappingHints">
/// Hints that can be used by the <see cref="ITypeMappingSource" /> to create data types with appropriate
/// facets for the converted data.
/// </param>
public TimeOnlyToStringConverter(ConverterMappingHints? mappingHints)
: base(
ToString(),
ToTimeOnly(),
DefaultHints.With(mappingHints))
{
}

/// <summary>
/// A <see cref="ValueConverterInfo" /> for the default use of this converter.
/// </summary>
public static ValueConverterInfo DefaultInfo { get; }
= new(typeof(TimeOnly), typeof(string), i => new TimeOnlyToStringConverter(i.MappingHints), DefaultHints);
}
45 changes: 45 additions & 0 deletions src/EFCore/Storage/ValueConversion/TimeOnlyToTicksConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore.Storage.ValueConversion;

/// <summary>
/// Converts <see cref="TimeOnly" /> to and <see cref="TimeOnly.Ticks" />.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
public class TimeOnlyToTicksConverter : ValueConverter<TimeOnly, long>
{
/// <summary>
/// Creates a new instance of this converter.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
public TimeOnlyToTicksConverter()
: this(null)
{
}

/// <summary>
/// Creates a new instance of this converter.
/// </summary>
/// <remarks>
/// See <see href="https://aka.ms/efcore-docs-value-converters">EF Core value converters</see> for more information and examples.
/// </remarks>
/// <param name="mappingHints">
/// Hints that can be used by the <see cref="ITypeMappingSource" /> to create data types with appropriate
/// facets for the converted data.
/// </param>
public TimeOnlyToTicksConverter(ConverterMappingHints? mappingHints)
: base(v => v.Ticks, v => new TimeOnly(v), mappingHints)
{
}

/// <summary>
/// A <see cref="ValueConverterInfo" /> for the default use of this converter.
/// </summary>
public static ValueConverterInfo DefaultInfo { get; }
= new(typeof(TimeOnly), typeof(long), i => new TimeOnlyToTicksConverter(i.MappingHints));
}
Loading

0 comments on commit 482b15c

Please sign in to comment.