diff --git a/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs b/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs
index e484cb56e7..d9efdfb2b9 100644
--- a/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs
+++ b/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs
@@ -205,6 +205,7 @@ public override void Generate(IModel model, CSharpRuntimeAnnotationCodeGenerator
annotations.Remove(NpgsqlAnnotationNames.DatabaseTemplate);
annotations.Remove(NpgsqlAnnotationNames.Tablespace);
annotations.Remove(NpgsqlAnnotationNames.CollationDefinitionPrefix);
+ annotations.Remove(NpgsqlAnnotationNames.Encoding);
#pragma warning disable CS0618
annotations.Remove(NpgsqlAnnotationNames.DefaultColumnCollation);
@@ -232,6 +233,7 @@ public override void Generate(IRelationalModel model, CSharpRuntimeAnnotationCod
annotations.Remove(NpgsqlAnnotationNames.DatabaseTemplate);
annotations.Remove(NpgsqlAnnotationNames.Tablespace);
annotations.Remove(NpgsqlAnnotationNames.CollationDefinitionPrefix);
+ annotations.Remove(NpgsqlAnnotationNames.Encoding);
#pragma warning disable CS0618
annotations.Remove(NpgsqlAnnotationNames.DefaultColumnCollation);
diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlModelBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlModelBuilderExtensions.cs
index 6650eb824e..5fd0fc2954 100644
--- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlModelBuilderExtensions.cs
+++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlModelBuilderExtensions.cs
@@ -653,6 +653,20 @@ public static ModelBuilder UseTablespace(
#endregion
+ #region Encoding
+ ///
+ /// Specifies the encoding to use when creating a new database for this model.
+ ///
+ public static ModelBuilder UseDatabaseEncoding(this ModelBuilder modelBuilder, string encoding)
+ {
+ Check.NotNull(modelBuilder, nameof(modelBuilder));
+ Check.NotEmpty(encoding, nameof(encoding));
+
+ modelBuilder.Model.SetDatabaseEncoding(encoding);
+ return modelBuilder;
+ }
+ #endregion
+
#region Collation management
///
diff --git a/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlModelExtensions.cs b/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlModelExtensions.cs
index a69ccf8ac7..0699d1e052 100644
--- a/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlModelExtensions.cs
+++ b/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlModelExtensions.cs
@@ -516,4 +516,24 @@ public static IReadOnlyList GetCollations(this IReadOnlyModel
=> PostgresCollation.GetCollations(model).ToArray();
#endregion Collation management
+
+ #region Encoding
+ ///
+ /// 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.
+ ///
+ public static string? GetEncoding(this IReadOnlyModel model)
+ => (string?)model[NpgsqlAnnotationNames.Encoding];
+
+ ///
+ /// 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.
+ ///
+ public static void SetDatabaseEncoding(this IMutableModel model, string? encoding)
+ => model.SetOrRemoveAnnotation(NpgsqlAnnotationNames.Encoding, encoding);
+ #endregion
}
diff --git a/src/EFCore.PG/Metadata/Conventions/NpgsqlRuntimeModelConvention.cs b/src/EFCore.PG/Metadata/Conventions/NpgsqlRuntimeModelConvention.cs
index 341fd802b7..ae06acdf4a 100644
--- a/src/EFCore.PG/Metadata/Conventions/NpgsqlRuntimeModelConvention.cs
+++ b/src/EFCore.PG/Metadata/Conventions/NpgsqlRuntimeModelConvention.cs
@@ -33,6 +33,7 @@ protected override void ProcessModelAnnotations(
annotations.Remove(NpgsqlAnnotationNames.DatabaseTemplate);
annotations.Remove(NpgsqlAnnotationNames.Tablespace);
annotations.Remove(NpgsqlAnnotationNames.CollationDefinitionPrefix);
+ annotations.Remove(NpgsqlAnnotationNames.Encoding);
#pragma warning disable CS0618
annotations.Remove(NpgsqlAnnotationNames.DefaultColumnCollation);
diff --git a/src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs b/src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs
index 0f2dd325ef..8d9db80783 100644
--- a/src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs
+++ b/src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs
@@ -40,6 +40,14 @@ public static class NpgsqlAnnotationNames
///
public const string DatabaseTemplate = Prefix + "DatabaseTemplate";
+ ///
+ /// 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.
+ ///
+ public const string Encoding = Prefix + "Encoding";
+
///
/// 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
diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs
index fccab7d188..fc249a6689 100644
--- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs
+++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs
@@ -1044,6 +1044,14 @@ protected virtual void Generate(NpgsqlCreateDatabaseOperation operation, IModel?
.Append(DelimitIdentifier(operation.Collation));
}
+ if (!string.IsNullOrEmpty(operation.Encoding))
+ {
+ builder
+ .AppendLine()
+ .Append("ENCODING ")
+ .Append(DelimitIdentifier(operation.Encoding));
+ }
+
builder.AppendLine(";");
EndStatement(builder, suppressTransaction: true);
diff --git a/src/EFCore.PG/Migrations/Operations/NpgsqlCreateDatabaseOperation.cs b/src/EFCore.PG/Migrations/Operations/NpgsqlCreateDatabaseOperation.cs
index 88d92e5253..28f15baca6 100644
--- a/src/EFCore.PG/Migrations/Operations/NpgsqlCreateDatabaseOperation.cs
+++ b/src/EFCore.PG/Migrations/Operations/NpgsqlCreateDatabaseOperation.cs
@@ -23,4 +23,9 @@ public class NpgsqlCreateDatabaseOperation : DatabaseOperation
/// The PostgreSQL tablespace in which to create the database.
///
public virtual string? Tablespace { get; set; }
+
+ ///
+ /// The PostgreSQL encoding to use for the database.
+ ///
+ public virtual string? Encoding { get; set; }
}
diff --git a/src/EFCore.PG/Storage/Internal/NpgsqlDatabaseCreator.cs b/src/EFCore.PG/Storage/Internal/NpgsqlDatabaseCreator.cs
index 4034f5ef2d..655ebfa883 100644
--- a/src/EFCore.PG/Storage/Internal/NpgsqlDatabaseCreator.cs
+++ b/src/EFCore.PG/Storage/Internal/NpgsqlDatabaseCreator.cs
@@ -162,7 +162,8 @@ private IReadOnlyList CreateCreateOperations()
Name = connection.DbConnection.Database,
Template = designTimeModel.GetDatabaseTemplate(),
Collation = designTimeModel.GetCollation(),
- Tablespace = designTimeModel.GetTablespace()
+ Tablespace = designTimeModel.GetTablespace(),
+ Encoding = designTimeModel.GetEncoding(),
}
]);
}
diff --git a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs
index 2cf1b21d9b..66b196e3ec 100644
--- a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs
+++ b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs
@@ -65,6 +65,19 @@ public virtual void CreateDatabaseOperation_with_tablespace()
CREATE DATABASE some_db
TABLESPACE "MyTablespace";
+""");
+ }
+
+ [Fact]
+ public virtual void CreateDatabaseOperation_with_encoding()
+ {
+ Generate(new NpgsqlCreateDatabaseOperation { Name = "Northwind", Encoding = "UTF8" });
+
+ AssertSql(
+ """
+CREATE DATABASE "Northwind"
+ENCODING "UTF8";
+
""");
}