Skip to content

Commit

Permalink
Fix regression to allow custom value conversion mapping when the ClrT…
Browse files Browse the repository at this point in the history
…ype is of non-NTS type. plus added unit test.

 - regression introduced in commit [3ef628f](3ef628f#diff-4f1d25d8c94e4764d1beef032d7ecc17efaf6a2f592db3dab748bac1d7fc0446R87)

Refs #1921
  • Loading branch information
ANASGAUBA committed Jul 31, 2024
1 parent 8070305 commit 9dbad69
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 7 deletions.
1 change: 1 addition & 0 deletions Dependencies.targets
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<PackageReference Update="DotNetAnalyzers.DocumentationAnalyzers" Version="1.0.0-beta.59" />
<PackageReference Update="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Update="Microsoft.CodeAnalysis" Version="4.5.0" />
<PackageReference Update="Shouldly" Version="4.0.3" />
<PackageReference Update="Microsoft.CodeAnalysis.Features" Version="4.5.0" />
<PackageReference Update="Microsoft.CodeAnalysis.CSharp.Features" Version="4.5.0" />
<PackageReference Update="Microsoft.CodeAnalysis.VisualBasic.Features" Version="4.5.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,30 @@ public virtual RelationalTypeMapping FindMapping(in RelationalTypeMappingInfo ma
string defaultStoreType = null;
Type defaultClrType = null;

return (clrType != null
&& TryGetDefaultStoreType(clrType, out defaultStoreType))
|| (storeTypeName != null
&& _spatialStoreTypeMappings.TryGetValue(storeTypeName, out defaultClrType))
? (RelationalTypeMapping)Activator.CreateInstance(
var hasDefaultStoreType = clrType != null
&& TryGetDefaultStoreType(clrType, out defaultStoreType);
var hasDefaultClrType = storeTypeName != null
&& _spatialStoreTypeMappings.TryGetValue(storeTypeName, out defaultClrType);

if (!(hasDefaultStoreType || hasDefaultClrType))
{
return null;
}

// NOTE: If the incoming user-specified 'clrType' is of the known calculated 'defaultClrType', ONLY then proceeed
// with the creation of 'MySqlGeometryTypeMapping'.
clrType = clrType == null
? defaultClrType
: clrType.IsAssignableFrom(defaultClrType)
? clrType
: null;
return clrType == null
? null
: (RelationalTypeMapping)Activator.CreateInstance(
typeof(MySqlGeometryTypeMapping<>).MakeGenericType(clrType ?? defaultClrType ?? typeof(Geometry)),
_geometryServices,
storeTypeName ?? defaultStoreType ?? "geometry",
_options)
: null;
_options);
}

private static bool TryGetDefaultStoreType(Type type, out string defaultStoreType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Shouldly" />
</ItemGroup>

<ItemGroup Condition="'$(LocalEFCoreRepository)' == ''">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.NTS;

using System;
using System.Linq;
using System.Threading.Tasks;

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NetTopologySuite.Geometries;
using Pomelo.EntityFrameworkCore.MySql.Tests;
using Shouldly;
using Xunit;

public class CustomValueConvertersForNonNTSClrTypesMySqlTest
{
[Fact]
public async Task NonNTS_ClrType_CanBe_Mapped_to_CustomValueConverters()
{
var services = new ServiceCollection()
.AddDbContext<CustomDbContext>()
.AddSingleton(
new DbContextOptionsBuilder<CustomDbContext>()
.UseMySql(
AppConfig.ConnectionString,
AppConfig.ServerVersion,
options =>
{
options.UseNetTopologySuite();
})
.EnableSensitiveDataLogging()
.LogTo(Console.WriteLine, LogLevel.Debug)
.Options);

var provider = services.BuildServiceProvider();
await using var context = provider.GetRequiredService<CustomDbContext>();

// Validate `MySqlNetTopologySuiteTypeMappingSourcePlugin.FindMapping()` doesn't throw.
await Should.NotThrowAsync(context.Database.EnsureDeletedAsync());
await Should.NotThrowAsync(context.Database.EnsureCreatedAsync());
}
}

public sealed class CustomDbContext(DbContextOptions<CustomDbContext> options) : DbContext(options)
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var testClass = modelBuilder.Entity<TestClass>();
testClass.Property(t => t.Vertices)
.HasColumnType("GEOMETRY")
.HasConversion(new MysqlGeometryWkbValueConverter());

var testClass2 = modelBuilder.Entity<TestClass2>();
testClass2.Property(t => t.Vertices)
.HasColumnType("GEOMETRY");
}
}

public class TestClass
{
public int Id { get; set; }
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public byte[] Vertices { get; set; }
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
}

public class TestClass2
{
public int Id { get; set; }

#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public Geometry Vertices { get; set; }
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
}

/// <summary>
/// MySql's internal geometry format is WKB with an initial 4
/// bytes for the SRID:
/// https://dev.mysql.com/doc/refman/5.7/en/gis-data-formats.html
/// </summary>
public class MysqlGeometryWkbValueConverter : ValueConverter<byte[], byte[]>
{
public MysqlGeometryWkbValueConverter()
: base(
clr => AddSRID(clr),
col => StripSRID(col))
{
}

private static byte[] AddSRID(byte[] wkb) =>
new byte[] { 0, 0, 0, 0, }.Concat(wkb).ToArray();

private static byte[] StripSRID(byte[] col) =>
col.Skip(4).ToArray();
}

0 comments on commit 9dbad69

Please sign in to comment.