Skip to content

Commit

Permalink
Add default type mappings for remaining complex types to support comp…
Browse files Browse the repository at this point in the history
…iled models in EF Core 8.
  • Loading branch information
lauxjpn committed Feb 12, 2024
1 parent 4f1acb0 commit 9760132
Show file tree
Hide file tree
Showing 16 changed files with 286 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ private SqlExpression ApplyPathLocationTypeMapping(SqlExpression expression)
sqlConstantExpression.TypeMapping is MySqlStringTypeMapping stringTypeMapping &&
!stringTypeMapping.IsUnquoted)
{
pathLocation = sqlConstantExpression.ApplyTypeMapping(stringTypeMapping.Clone(true));
pathLocation = sqlConstantExpression.ApplyTypeMapping(stringTypeMapping.Clone(unquoted: true));
}

return pathLocation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ namespace Pomelo.EntityFrameworkCore.MySql.Json.Microsoft.Storage.Internal
{
public class MySqlJsonMicrosoftTypeMapping<T> : MySqlJsonTypeMapping<T>
{
public static new MySqlJsonMicrosoftTypeMapping<T> Default { get; } = new("json", null, null, false, true);

// Called via reflection.
// ReSharper disable once UnusedMember.Global
public MySqlJsonMicrosoftTypeMapping(
Expand Down Expand Up @@ -48,6 +50,13 @@ protected MySqlJsonMicrosoftTypeMapping(
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
=> new MySqlJsonMicrosoftTypeMapping<T>(parameters, MySqlDbType, NoBackslashEscapes, ReplaceLineBreaksWithCharFunction);

protected override RelationalTypeMapping Clone(bool? noBackslashEscapes = null, bool? replaceLineBreaksWithCharFunction = null)
=> new MySqlJsonMicrosoftTypeMapping<T>(
Parameters,
MySqlDbType,
noBackslashEscapes ?? NoBackslashEscapes,
replaceLineBreaksWithCharFunction ?? ReplaceLineBreaksWithCharFunction);

public override Expression GenerateCodeLiteral(object value)
=> value switch
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public MySqlJsonMicrosoftJsonDocumentValueConverter()
{
}

private static string ConvertToProviderCore(JsonDocument v)
public static string ConvertToProviderCore(JsonDocument v)
{
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
Expand All @@ -27,7 +27,7 @@ private static string ConvertToProviderCore(JsonDocument v)
return Encoding.UTF8.GetString(stream.ToArray());
}

private static JsonDocument ConvertFromProviderCore(string v)
public static JsonDocument ConvertFromProviderCore(string v)
=> JsonDocument.Parse(v);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public MySqlJsonMicrosoftJsonElementValueConverter()
{
}

private static string ConvertToProviderCore(JsonElement v)
public static string ConvertToProviderCore(JsonElement v)
{
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
Expand All @@ -24,7 +24,7 @@ private static string ConvertToProviderCore(JsonElement v)
return Encoding.UTF8.GetString(stream.ToArray());
}

private static JsonElement ConvertFromProviderCore(string v)
public static JsonElement ConvertFromProviderCore(string v)
=> JsonDocument.Parse(v).RootElement;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ public MySqlJsonMicrosoftPocoValueConverter()
{
}

private static string ConvertToProviderCore(T v)
public static string ConvertToProviderCore(T v)
=> JsonSerializer.Serialize(v);

private static T ConvertFromProviderCore(string v)
public static T ConvertFromProviderCore(string v)
=> JsonSerializer.Deserialize<T>(v);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ public MySqlJsonMicrosoftStringValueConverter()
{
}

private static string ConvertToProviderCore(string v)
public static string ConvertToProviderCore(string v)
=> ProcessJsonString(v);

private static string ConvertFromProviderCore(string v)
public static string ConvertFromProviderCore(string v)
=> ProcessJsonString(v);

internal static string ProcessJsonString(string v)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ private SqlExpression ApplyPathLocationTypeMapping(SqlExpression expression)
sqlConstantExpression.TypeMapping is MySqlStringTypeMapping stringTypeMapping &&
!stringTypeMapping.IsUnquoted)
{
pathLocation = sqlConstantExpression.ApplyTypeMapping(stringTypeMapping.Clone(true));
pathLocation = sqlConstantExpression.ApplyTypeMapping(stringTypeMapping.Clone(unquoted: true));
}

return pathLocation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace Pomelo.EntityFrameworkCore.MySql.Json.Newtonsoft.Storage.Internal
{
public class MySqlJsonNewtonsoftTypeMapping<T> : MySqlJsonTypeMapping<T>
{
public static new MySqlJsonNewtonsoftTypeMapping<T> Default { get; } = new("json", null, null, false, true);

// Called via reflection.
// ReSharper disable once UnusedMember.Global
public MySqlJsonNewtonsoftTypeMapping(
Expand Down Expand Up @@ -45,6 +47,13 @@ protected MySqlJsonNewtonsoftTypeMapping(
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
=> new MySqlJsonNewtonsoftTypeMapping<T>(parameters, MySqlDbType, NoBackslashEscapes, ReplaceLineBreaksWithCharFunction);

protected override RelationalTypeMapping Clone(bool? noBackslashEscapes = null, bool? replaceLineBreaksWithCharFunction = null)
=> new MySqlJsonNewtonsoftTypeMapping<T>(
Parameters,
MySqlDbType,
noBackslashEscapes ?? NoBackslashEscapes,
replaceLineBreaksWithCharFunction ?? ReplaceLineBreaksWithCharFunction);

public override Expression GenerateCodeLiteral(object value)
=> value switch
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Pomelo Foundation. All rights reserved.
// Licensed under the MIT. See LICENSE in the project root for license information.

using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Pomelo.EntityFrameworkCore.MySql.Storage.Internal;

namespace Pomelo.EntityFrameworkCore.MySql.Design.Internal;

public class MySqlCSharpRuntimeAnnotationCodeGenerator : RelationalCSharpRuntimeAnnotationCodeGenerator
{
public MySqlCSharpRuntimeAnnotationCodeGenerator(
CSharpRuntimeAnnotationCodeGeneratorDependencies dependencies,
RelationalCSharpRuntimeAnnotationCodeGeneratorDependencies relationalDependencies)
: base(dependencies, relationalDependencies)
{
}

public override bool Create(
CoreTypeMapping typeMapping,
CSharpRuntimeAnnotationCodeGeneratorParameters parameters,
ValueComparer valueComparer = null,
ValueComparer keyValueComparer = null,
ValueComparer providerValueComparer = null)
{
var result = base.Create(typeMapping, parameters, valueComparer, keyValueComparer, providerValueComparer);

if (typeMapping is IMySqlCSharpRuntimeAnnotationTypeMappingCodeGenerator extension)
{
extension.Create(parameters, Dependencies);
}

return result;
}
}
2 changes: 2 additions & 0 deletions src/EFCore.MySql/Design/Internal/MySqlDesignTimeServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Pomelo.EntityFrameworkCore.MySql.Scaffolding.Internal;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.EntityFrameworkCore.Scaffolding;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -14,6 +15,7 @@ public virtual void ConfigureDesignTimeServices(IServiceCollection serviceCollec
{
serviceCollection.AddEntityFrameworkMySql();
new EntityFrameworkRelationalDesignServicesBuilder(serviceCollection)
.TryAdd<ICSharpRuntimeAnnotationCodeGenerator, MySqlCSharpRuntimeAnnotationCodeGenerator>()
.TryAdd<IAnnotationCodeGenerator, MySqlAnnotationCodeGenerator>()
.TryAdd<IDatabaseModelFactory, MySqlDatabaseModelFactory>()
.TryAdd<IProviderConfigurationCodeGenerator, MySqlCodeGenerator>()
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore.MySql/Migrations/MySqlMigrationsSqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,7 @@ protected override void DefaultValue(

if (typeMapping is IDefaultValueCompatibilityAware defaultValueCompatibilityAware)
{
typeMapping = defaultValueCompatibilityAware.Clone(true);
typeMapping = defaultValueCompatibilityAware.Clone(isDefaultValueCompatible: true);
}

var sqlLiteralDefaultValue = typeMapping.GenerateSqlLiteral(defaultValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public MySqlJsonPocoTranslator(
{
_typeMappingSource = typeMappingSource;
_sqlExpressionFactory = sqlExpressionFactory;
_unquotedStringTypeMapping = ((MySqlStringTypeMapping)_typeMappingSource.FindMapping(typeof(string))).Clone(true);
_unquotedStringTypeMapping = ((MySqlStringTypeMapping)_typeMappingSource.FindMapping(typeof(string))).Clone(unquoted: true);
_intTypeMapping = _typeMappingSource.FindMapping(typeof(int));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Pomelo Foundation. All rights reserved.
// Licensed under the MIT. See LICENSE in the project root for license information.

using Microsoft.EntityFrameworkCore.Design.Internal;

namespace Pomelo.EntityFrameworkCore.MySql.Storage.Internal;

public interface IMySqlCSharpRuntimeAnnotationTypeMappingCodeGenerator
{
void Create(
CSharpRuntimeAnnotationCodeGeneratorParameters codeGeneratorParameters,
CSharpRuntimeAnnotationCodeGeneratorDependencies codeGeneratorDependencies);
}
68 changes: 59 additions & 9 deletions src/EFCore.MySql/Storage/Internal/MySqlGuidTypeMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@
// Licensed under the MIT. See LICENSE in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Json;
using MySqlConnector;
using Pomelo.EntityFrameworkCore.MySql.Utilities;

namespace Pomelo.EntityFrameworkCore.MySql.Storage.Internal
{
public class MySqlGuidTypeMapping : GuidTypeMapping, IJsonSpecificTypeMapping
public class MySqlGuidTypeMapping : GuidTypeMapping, IJsonSpecificTypeMapping, IMySqlCSharpRuntimeAnnotationTypeMappingCodeGenerator
{
private readonly MySqlGuidFormat _guidFormat;
public static new MySqlGuidTypeMapping Default { get; } = new(MySqlGuidFormat.Char36);

public static new MySqlGuidTypeMapping Default { get; } = new(MySqlGuidFormat.Default);
public virtual MySqlGuidFormat GuidFormat { get; }

public MySqlGuidTypeMapping(MySqlGuidFormat guidFormat)
: this(new RelationalTypeMappingParameters(
Expand All @@ -33,18 +35,21 @@ public MySqlGuidTypeMapping(MySqlGuidFormat guidFormat)
protected MySqlGuidTypeMapping(RelationalTypeMappingParameters parameters, MySqlGuidFormat guidFormat)
: base(parameters)
{
_guidFormat = guidFormat;
GuidFormat = guidFormat;
}

protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
=> new MySqlGuidTypeMapping(parameters, _guidFormat);
=> new MySqlGuidTypeMapping(parameters, GuidFormat);

public virtual RelationalTypeMapping Clone(MySqlGuidFormat guidFormat)
=> new MySqlGuidTypeMapping(Parameters, guidFormat);

public virtual bool IsCharBasedStoreType
=> GetStoreType(_guidFormat) == "char";
=> GetStoreType(GuidFormat) == "char";

protected override string GenerateNonNullSqlLiteral(object value)
{
switch (_guidFormat)
switch (GuidFormat)
{
case MySqlGuidFormat.Char36:
return $"'{value:D}'";
Expand All @@ -55,7 +60,7 @@ protected override string GenerateNonNullSqlLiteral(object value)
case MySqlGuidFormat.Binary16:
case MySqlGuidFormat.TimeSwapBinary16:
case MySqlGuidFormat.LittleEndianBinary16:
return "0x" + Convert.ToHexString(GetBytesFromGuid(_guidFormat, (Guid)value));
return "0x" + Convert.ToHexString(GetBytesFromGuid(GuidFormat, (Guid)value));

case MySqlGuidFormat.None:
case MySqlGuidFormat.Default:
Expand Down Expand Up @@ -132,5 +137,50 @@ protected static byte[] GetBytesFromGuid(MySqlGuidFormat guidFormat, Guid guid)
/// </summary>
public virtual RelationalTypeMapping CloneAsJsonCompatible()
=> new MySqlGuidTypeMapping(MySqlGuidFormat.Char36);

void IMySqlCSharpRuntimeAnnotationTypeMappingCodeGenerator.Create(
CSharpRuntimeAnnotationCodeGeneratorParameters codeGeneratorParameters,
CSharpRuntimeAnnotationCodeGeneratorDependencies codeGeneratorDependencies)
{
var defaultTypeMapping = Default;
if (defaultTypeMapping == this)
{
return;
}

var code = codeGeneratorDependencies.CSharpHelper;

var cloneParameters = new List<string>();

if (GuidFormat != defaultTypeMapping.GuidFormat)
{
cloneParameters.Add($"guidFormat: {code.Literal(GuidFormat, true)}");
}

if (cloneParameters.Any())
{
var mainBuilder = codeGeneratorParameters.MainBuilder;

mainBuilder.AppendLine(";");

mainBuilder
.AppendLine($"{codeGeneratorParameters.TargetName}.TypeMapping = (({code.Reference(GetType())}){codeGeneratorParameters.TargetName}.TypeMapping).Clone(")
.IncrementIndent();

for (var i = 0; i < cloneParameters.Count; i++)
{
if (i > 0)
{
mainBuilder.AppendLine(",");
}

mainBuilder.Append(cloneParameters[i]);
}

mainBuilder
.Append(")")
.DecrementIndent();
}
}
}
}
Loading

0 comments on commit 9760132

Please sign in to comment.