Skip to content

Commit

Permalink
Switch to new EF Core plugin model
Browse files Browse the repository at this point in the history
Notes:

* Added some missing NTS translations
* The new EF Core plugin model doesn't yet support specifying
  evaluatable (dotnet/efcore#13454),
  so we currently hack that up inside the main provider using type
  names as strings.

Fixes npgsql#658
  • Loading branch information
roji committed Oct 29, 2018
1 parent 89b9742 commit 84fb709
Show file tree
Hide file tree
Showing 51 changed files with 1,937 additions and 1,180 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
.idea/
.vs/
[Bb]in/
[Bb]uild/
[Oo]bj/
[Oo]bj/
artifacts/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;

namespace Npgsql.EntityFrameworkCore.PostgreSQL.Design.Internal
{
public class NpgsqlNetTopologySuiteDesignTimeServices : IDesignTimeServices
{
public virtual void ConfigureDesignTimeServices(IServiceCollection serviceCollection)
=> serviceCollection
.AddSingleton<IRelationalTypeMappingSourcePlugin, NpgsqlNetTopologySuiteTypeMappingSourcePlugin>()
.TryAddSingleton<INpgsqlNetTopologySuiteOptions, NpgsqlNetTopologySuiteOptions>();

}
}
6 changes: 6 additions & 0 deletions src/EFCore.PG.NTS/EFCore.PG.NTS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
<ItemGroup>
<Compile Include="..\Shared\*.cs" />
</ItemGroup>
<ItemGroup>
<None Include="build\**\*">
<Pack>True</Pack>
<PackagePath>build</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EFCore.PG\EFCore.PG.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using GeoAPI;
using GeoAPI.Geometries;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Npgsql;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities;

namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// NetTopologySuite specific extension methods for <see cref="NpgsqlDbContextOptionsBuilder"/>.
/// </summary>
public static class NpgsqlNetTopologySuiteDbContextOptionsBuilderExtensions
{
/// <summary>
/// Use NetTopologySuite to access SQL Server spatial data.
/// </summary>
/// <returns>
/// The options builder so that further configuration can be chained.
/// </returns>
public static NpgsqlDbContextOptionsBuilder UseNetTopologySuite(
[NotNull] this NpgsqlDbContextOptionsBuilder optionsBuilder,
ICoordinateSequenceFactory coordinateSequenceFactory = null,
IPrecisionModel precisionModel = null,
Ordinates handleOrdinates = Ordinates.None,
bool geographyAsDefault = false)
{
Check.NotNull(optionsBuilder, nameof(optionsBuilder));

// TODO: Global-only setup at the ADO.NET level for now, optionally allow per-connection?
NpgsqlConnection.GlobalTypeMapper.UseNetTopologySuite(coordinateSequenceFactory, precisionModel, handleOrdinates, geographyAsDefault);

var coreOptionsBuilder = ((IRelationalDbContextOptionsBuilderInfrastructure)optionsBuilder).OptionsBuilder;

var extension = coreOptionsBuilder.Options.FindExtension<NpgsqlNetTopologySuiteOptionsExtension>()
?? new NpgsqlNetTopologySuiteOptionsExtension();

if (geographyAsDefault)
extension = extension.WithGeographyDefault();

((IDbContextOptionsBuilderInfrastructure)coreOptionsBuilder).AddOrUpdateExtension(extension);

return optionsBuilder;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NetTopologySuite;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities;

namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite extension methods for <see cref="IServiceCollection" />.
/// </summary>
public static class NpgsqlNetTopologySuiteServiceCollectionExtensions
{
/// <summary>
/// Adds the services required for NetTopologySuite support in the Npgsql provider for Entity Framework.
/// </summary>
/// <param name="serviceCollection">The <see cref="IServiceCollection" /> to add services to.</param>
/// <returns>The same service collection so that multiple calls can be chained.</returns>
public static IServiceCollection AddEntityFrameworkNpgsqlNetTopologySuite(
[NotNull] this IServiceCollection serviceCollection)
{
Check.NotNull(serviceCollection, nameof(serviceCollection));

new EntityFrameworkRelationalServicesBuilder(serviceCollection)
.TryAdd<ISingletonOptions, INpgsqlNetTopologySuiteOptions>(p => p.GetService<INpgsqlNetTopologySuiteOptions>())
.TryAddProviderSpecificServices(
x => x
.TryAddSingletonEnumerable<IRelationalTypeMappingSourcePlugin, NpgsqlNetTopologySuiteTypeMappingSourcePlugin>()
.TryAddSingletonEnumerable<IMethodCallTranslatorPlugin, NpgsqlNetTopologySuiteMethodCallTranslatorPlugin>()
.TryAddSingletonEnumerable<IMemberTranslatorPlugin, NpgsqlNetTopologySuiteMemberTranslatorPlugin>()
.TryAddSingleton<INpgsqlNetTopologySuiteOptions, NpgsqlNetTopologySuiteOptions>());


return serviceCollection;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal
{
/// <summary>
/// Represents options for Npgsql NetTopologySuite that can only be set at the <see cref="IServiceProvider"/> singleton level.
/// </summary>
public interface INpgsqlNetTopologySuiteOptions : ISingletonOptions
{
/// <summary>
/// True if geography is to be used by default instead of geometry
/// </summary>
bool IsGeographyDefault { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities;

namespace Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal
{
public class NpgsqlNetTopologySuiteOptionsExtension : IDbContextOptionsExtensionWithDebugInfo
{
bool _isGeographyDefault;
string _logFragment;

public NpgsqlNetTopologySuiteOptionsExtension() {}

protected NpgsqlNetTopologySuiteOptionsExtension([NotNull] NpgsqlNetTopologySuiteOptionsExtension copyFrom)
=> _isGeographyDefault = copyFrom._isGeographyDefault;

protected virtual NpgsqlNetTopologySuiteOptionsExtension Clone() => new NpgsqlNetTopologySuiteOptionsExtension(this);

public virtual bool ApplyServices(IServiceCollection services)
{
services.AddEntityFrameworkNpgsqlNetTopologySuite();

return false;
}

public virtual bool IsGeographyDefault => _isGeographyDefault;

public virtual NpgsqlNetTopologySuiteOptionsExtension WithGeographyDefault(bool isGeographyDefault = true)
{
var clone = Clone();

clone._isGeographyDefault = isGeographyDefault;

return clone;
}

public virtual long GetServiceProviderHashCode() => _isGeographyDefault ? 541 : 0;

public virtual void PopulateDebugInfo(IDictionary<string, string> debugInfo)
{
Check.NotNull(debugInfo, nameof(debugInfo));

debugInfo["NpgsqlNetTopologySuite:" + nameof(IsGeographyDefault)]
= (_isGeographyDefault ? 541 : 0).ToString(CultureInfo.InvariantCulture);
}

public virtual void Validate(IDbContextOptions options)
{
Check.NotNull(options, nameof(options));

var internalServiceProvider = options.FindExtension<CoreOptionsExtension>()?.InternalServiceProvider;
if (internalServiceProvider != null)
{
using (var scope = internalServiceProvider.CreateScope())
{
if (scope.ServiceProvider.GetService<IEnumerable<IRelationalTypeMappingSourcePlugin>>()
?.Any(s => s is NpgsqlNetTopologySuiteTypeMappingSourcePlugin) != true)
{
throw new InvalidOperationException($"{nameof(NpgsqlNetTopologySuiteDbContextOptionsBuilderExtensions.UseNetTopologySuite)} requires {nameof(NpgsqlNetTopologySuiteServiceCollectionExtensions.AddEntityFrameworkNpgsqlNetTopologySuite)} to be called on the internal service provider used.");
}
}
}
}

[NotNull]
public virtual string LogFragment
{
get
{
if (_logFragment == null)
{
var builder = new StringBuilder("using NetTopologySuite");
if (_isGeographyDefault)
builder.Append(" (geography by default)");
builder.Append(' ');

_logFragment = builder.ToString();
}

return _logFragment;
}
}
}
}
24 changes: 24 additions & 0 deletions src/EFCore.PG.NTS/Internal/NpgsqlNetTopologySuiteOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal;

namespace Npgsql.EntityFrameworkCore.PostgreSQL.Internal
{
/// <inheritdoc />
public class NpgsqlNetTopologySuiteOptions : INpgsqlNetTopologySuiteOptions
{
/// <inheritdoc />
public bool IsGeographyDefault { get; set; }

/// <inheritdoc />
public void Initialize(IDbContextOptions options)
{
var npgsqlNtsOptions = options.FindExtension<NpgsqlNetTopologySuiteOptionsExtension>() ?? new NpgsqlNetTopologySuiteOptionsExtension();

IsGeographyDefault = npgsqlNtsOptions.IsGeographyDefault;
}

/// <inheritdoc />
public void Validate(IDbContextOptions options) {}
}
}
32 changes: 0 additions & 32 deletions src/EFCore.PG.NTS/NetTopologySuiteDbContextOptionsExtensions.cs

This file was deleted.

46 changes: 0 additions & 46 deletions src/EFCore.PG.NTS/NetTopologySuiteGeographyTypeMapping.cs

This file was deleted.

46 changes: 0 additions & 46 deletions src/EFCore.PG.NTS/NetTopologySuiteGeometryTypeMapping.cs

This file was deleted.

Loading

0 comments on commit 84fb709

Please sign in to comment.