Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions doc/mapping/enum.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ However, the Npgsql provider also allows you to map your CLR enums to [database
First, you must specify the PostgreSQL enum type on your model, just like you would with tables, sequences or other databases objects:

```c#
protected override void OnModelCreating(ModelBuilder builder) {
builder.ForNpgsqlHasEnum("Mood", new[] { "happy", "sad" });
}
protected override void OnModelCreating(ModelBuilder builder)
=> builder.ForNpgsqlHasEnum<Mood>();
```

This causes the EF Core provider to create your data enum type, `Mood`, with two labels: `happy` and `sad`. This will cause the appropriate migration to be created.
Expand All @@ -22,9 +21,7 @@ Even if your database enum is created, Npgsql has to know about it, and especial

```c#
static MyDbContext()
{
NpgsqlConnection.GlobalTypeMapper.MapEnum<Mood>("Mood");
}
=> NpgsqlConnection.GlobalTypeMapper.MapEnum<Mood>();
```

This code lets Npgsql know that your CLR enum type, `Mood`, should be mapped to a database enum called `Mood`.
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore.PG.NTS/EFCore.PG.NTS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Npgsql.NetTopologySuite" Version="1.0.2" />
<PackageReference Include="Npgsql" Version="4.0.3-ci.1170+sha.c6c404330" />
<PackageReference Include="Npgsql" Version="4.0.3-ci.1272+sha.b3fc7da6f" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion src/EFCore.PG.NodaTime/EFCore.PG.NodaTime.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<ProjectReference Include="..\EFCore.PG\EFCore.PG.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Npgsql" Version="4.0.3-ci.1170+sha.c6c404330" />
<PackageReference Include="Npgsql" Version="4.0.3-ci.1272+sha.b3fc7da6f" />
<PackageReference Include="Npgsql.NodaTime" Version="1.0.0" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion src/EFCore.PG/EFCore.PG.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.0-preview1-34941" PrivateAssets="none" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.2.0-preview1-34941" PrivateAssets="none" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="2.2.0-preview1-34941" PrivateAssets="none" />
<PackageReference Include="Npgsql" Version="4.0.3-ci.1170+sha.c6c404330" />
<PackageReference Include="Npgsql" Version="4.0.3-ci.1272+sha.b3fc7da6f" />
</ItemGroup>
<ItemGroup>
<None Update="Properties\NpgsqlStrings.Designer.tt">
Expand Down
165 changes: 152 additions & 13 deletions src/EFCore.PG/Extensions/NpgsqlModelBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,58 @@
using JetBrains.Annotations;
#region License

// The PostgreSQL License
//
// Copyright (C) 2016 The Npgsql Development Team
//
// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose, without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
// and this paragraph and the following two paragraphs appear in all copies.
//
// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

#endregion

using System;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities;
using Npgsql.NameTranslation;
using NpgsqlTypes;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// Npgsql specific extension methods for <see cref="ModelBuilder" />.
/// Npgsql specific extension methods for <see cref="ModelBuilder"/>.
/// </summary>
[PublicAPI]
public static class NpgsqlModelBuilderExtensions
{
#region Sequences

/// <summary>
/// Configures the model to use a sequence-based hi-lo pattern to generate values for properties
/// marked as <see cref="ValueGenerated.OnAdd" />, when targeting PostgreSQL.
/// Configures the model to use a sequence-based hi-lo pattern to generate values for properties
/// marked as <see cref="ValueGenerated.OnAdd" />, when targeting PostgreSQL.
/// </summary>
/// <param name="modelBuilder"> The model builder. </param>
/// <param name="name"> The name of the sequence. </param>
/// <param name="schema">The schema of the sequence. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
/// <param name="modelBuilder">The model builder.</param>
/// <param name="name">The name of the sequence.</param>
/// <param name="schema">The schema of the sequence.</param>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public static ModelBuilder ForNpgsqlUseSequenceHiLo(
[NotNull] this ModelBuilder modelBuilder,
[CanBeNull] string name = null,
Expand All @@ -45,12 +79,12 @@ public static ModelBuilder ForNpgsqlUseSequenceHiLo(
}

/// <summary>
/// Configures the model to use the PostgreSQL SERIAL feature to generate values for properties
/// marked as <see cref="ValueGenerated.OnAdd" />, when targeting PostgreSQL. This is the default
/// behavior when targeting PostgreSQL.
/// Configures the model to use the PostgreSQL SERIAL feature to generate values for properties
/// marked as <see cref="ValueGenerated.OnAdd" />, when targeting PostgreSQL. This is the default
/// behavior when targeting PostgreSQL.
/// </summary>
/// <param name="modelBuilder"> The model builder. </param>
/// <returns> The same builder instance so that multiple calls can be chained. </returns>
/// <param name="modelBuilder">The model builder.</param>
/// <returns>The same builder instance so that multiple calls can be chained.</returns>
public static ModelBuilder ForNpgsqlUseSerialColumns(
[NotNull] this ModelBuilder modelBuilder)
{
Expand All @@ -65,6 +99,8 @@ public static ModelBuilder ForNpgsqlUseSerialColumns(
return modelBuilder;
}

#endregion

#region Identity

/// <summary>
Expand Down Expand Up @@ -134,6 +170,8 @@ public static ModelBuilder ForNpgsqlUseIdentityColumns(

#endregion Identity

#region Extensions

public static ModelBuilder HasPostgresExtension(
[NotNull] this ModelBuilder modelBuilder,
[NotNull] string name)
Expand All @@ -145,6 +183,25 @@ public static ModelBuilder HasPostgresExtension(
return modelBuilder;
}

#endregion

#region Enums

/// <summary>
/// Registers a user-defined enum type in the model.
/// </summary>
/// <param name="modelBuilder">The model builder in which to create the enum type.</param>
/// <param name="schema">The schema in which to create the enum type.</param>
/// <param name="name">The name of the enum type to create.</param>
/// <param name="labels">The enum label values.</param>
/// <returns>
/// The updated <see cref="ModelBuilder"/>.
/// </returns>
/// <remarks>
/// See: https://www.postgresql.org/docs/current/static/datatype-enum.html
/// </remarks>
/// <exception cref="ArgumentNullException">builder</exception>
[NotNull]
public static ModelBuilder ForNpgsqlHasEnum(
[NotNull] this ModelBuilder modelBuilder,
[CanBeNull] string schema,
Expand All @@ -159,12 +216,64 @@ public static ModelBuilder ForNpgsqlHasEnum(
return modelBuilder;
}

/// <summary>
/// Registers a user-defined enum type in the model.
/// </summary>
/// <param name="modelBuilder">The model builder in which to create the enum type.</param>
/// <param name="name">The name of the enum type to create.</param>
/// <param name="labels">The enum label values.</param>
/// <returns>
/// The updated <see cref="ModelBuilder"/>.
/// </returns>
/// <remarks>
/// See: https://www.postgresql.org/docs/current/static/datatype-enum.html
/// </remarks>
/// <exception cref="ArgumentNullException">builder</exception>
[NotNull]
public static ModelBuilder ForNpgsqlHasEnum(
[NotNull] this ModelBuilder modelBuilder,
[NotNull] string name,
[NotNull] string[] labels)
=> modelBuilder.ForNpgsqlHasEnum(null, name, labels);

/// <summary>
/// Registers a user-defined enum type in the model.
/// </summary>
/// <param name="modelBuilder">The model builder in which to create the enum type.</param>
/// <param name="schema">The schema in which to create the enum type.</param>
/// <param name="name">The name of the enum type to create.</param>
/// <param name="nameTranslator">
/// The translator for name and label inference.
/// Defaults to <see cref="NpgsqlSnakeCaseNameTranslator"/>.</param>
/// <typeparam name="TEnum"></typeparam>
/// <returns>
/// The updated <see cref="ModelBuilder"/>.
/// </returns>
/// <remarks>
/// See: https://www.postgresql.org/docs/current/static/datatype-enum.html
/// </remarks>
/// <exception cref="ArgumentNullException">builder</exception>
[NotNull]
public static ModelBuilder ForNpgsqlHasEnum<TEnum>(
[NotNull] this ModelBuilder modelBuilder,
[CanBeNull] string schema = null,
[CanBeNull] string name = null,
[CanBeNull] INpgsqlNameTranslator nameTranslator = null)
where TEnum : struct, Enum
{
if (nameTranslator == null)
nameTranslator = NpgsqlConnection.GlobalTypeMapper.DefaultNameTranslator;

return modelBuilder.ForNpgsqlHasEnum(
schema,
name ?? GetTypePgName<TEnum>(nameTranslator),
GetMemberPgNames<TEnum>(nameTranslator));
}

#endregion

#region Templates

public static ModelBuilder HasDatabaseTemplate(
[NotNull] this ModelBuilder modelBuilder,
[NotNull] string templateDatabaseName)
Expand All @@ -176,6 +285,10 @@ public static ModelBuilder HasDatabaseTemplate(
return modelBuilder;
}

#endregion

#region Ranges

/// <summary>
/// Registers a user-defined range type in the model.
/// </summary>
Expand Down Expand Up @@ -238,6 +351,10 @@ public static ModelBuilder ForNpgsqlHasRange(
[NotNull] string subtype)
=> ForNpgsqlHasRange(modelBuilder, null, name, subtype);

#endregion

#region Tablespaces

public static ModelBuilder ForNpgsqlUseTablespace(
[NotNull] this ModelBuilder modelBuilder,
[NotNull] string tablespace)
Expand All @@ -248,5 +365,27 @@ public static ModelBuilder ForNpgsqlUseTablespace(
modelBuilder.Model.Npgsql().Tablespace = tablespace;
return modelBuilder;
}

#endregion

#region Helpers

// See: https://github.com/npgsql/npgsql/blob/dev/src/Npgsql/TypeMapping/TypeMapperBase.cs#L132-L138
[NotNull]
static string GetTypePgName<TEnum>([NotNull] INpgsqlNameTranslator nameTranslator) where TEnum : struct, Enum
=> typeof(TEnum).GetCustomAttribute<PgNameAttribute>()?.PgName ??
nameTranslator.TranslateTypeName(typeof(TEnum).Name);

// See: https://github.com/npgsql/npgsql/blob/dev/src/Npgsql/TypeHandlers/EnumHandler.cs#L118-L129
[NotNull]
[ItemNotNull]
static string[] GetMemberPgNames<TEnum>([NotNull] INpgsqlNameTranslator nameTranslator) where TEnum : struct, Enum
=> typeof(TEnum)
.GetFields(BindingFlags.Static | BindingFlags.Public)
.Select(x => x.GetCustomAttribute<PgNameAttribute>()?.PgName ??
nameTranslator.TranslateMemberName(x.Name))
.ToArray();

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational.Specification.Tests" Version="2.2.0-preview1-34941" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0-preview1-34941" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0-preview1-34941" />
<PackageReference Update="Npgsql" Version="4.0.3-ci.1272" />
</ItemGroup>
</Project>
Loading