From 3da008e803f28759ea7946cc51436908705599c7 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 23 May 2016 11:08:37 +0300 Subject: [PATCH] Fix PG extension mechanism + generated UUID --- .../NpgsqlServiceCollectionExtensions.cs | 5 + .../Internal/NpgsqlModelValidator.cs | 7 +- .../Internal/NpgsqlMigrationsModelDiffer.cs | 104 +++++++++++++++ .../NpgsqlMigrationsSqlGenerator.cs | 14 +++ .../NpgsqlDropPostgresExtensionOperation.cs | 32 +++++ ...gsql.EntityFrameworkCore.PostgreSQL.csproj | 2 + .../Storage/Internal/NpgsqlDatabaseCreator.cs | 118 +++++++++--------- .../BatchingTest.cs | 2 + .../BuiltInDataTypesNpgsqlFixture.cs | 27 +--- .../GearsOfWarQueryNpgsqlFixture.cs | 8 ++ .../GraphUpdatesNpgsqlTest.cs | 7 ++ .../NpgsqlDatabaseCreatorTest.cs | 3 +- .../NpgsqlValueGenerationScenariosTest.cs | 11 +- 13 files changed, 252 insertions(+), 88 deletions(-) create mode 100644 src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/Internal/NpgsqlMigrationsModelDiffer.cs create mode 100644 src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/Operations/NpgsqlDropPostgresExtensionOperation.cs diff --git a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Extensions/NpgsqlServiceCollectionExtensions.cs b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Extensions/NpgsqlServiceCollectionExtensions.cs index 6b0a5388..225259db 100644 --- a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Extensions/NpgsqlServiceCollectionExtensions.cs +++ b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Extensions/NpgsqlServiceCollectionExtensions.cs @@ -78,6 +78,11 @@ public static IServiceCollection AddEntityFrameworkNpgsql([NotNull] this IServic { Check.NotNull(services, nameof(services)); + services.TryAdd(new ServiceCollection() + .AddScoped() + .AddScoped() + ); + services.AddRelational(); services.TryAddEnumerable(ServiceDescriptor diff --git a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Internal/NpgsqlModelValidator.cs b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Internal/NpgsqlModelValidator.cs index 7a72a24f..553cf8c2 100644 --- a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Internal/NpgsqlModelValidator.cs +++ b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Internal/NpgsqlModelValidator.cs @@ -33,15 +33,16 @@ protected virtual void EnsureUuidExtensionIfNeeded(IModel model) from e in model.GetEntityTypes() from p in e.GetProperties() where p.ClrType.UnwrapNullableType() == typeof(Guid) - let defaultValueSql = (string)_relationalExtensions.For(p).DefaultValueSql - where defaultValueSql != null && defaultValueSql.Contains("uuid_generate") + let defaultValueSql = _relationalExtensions.For(p).DefaultValueSql + where _relationalExtensions.For(p).DefaultValueSql?.StartsWith("uuid_generate") == true || + p.ValueGenerated == ValueGenerated.OnAdd select p ).FirstOrDefault(); if (generatedUuidProperty != null && model.Npgsql().PostgresExtensions.All(e => e.Name != "uuid-ossp")) { - ShowError(@"Database-generated UUIDs require the PostgreSQL uuid-ossp extension. Add .HasPostgresExtension(""uuid-ossp"") to your context's OnModelCreating."); + ShowError($@"Property {generatedUuidProperty.Name} on type {generatedUuidProperty.DeclaringEntityType.Name} is a database-generated uuid, which requires the PostgreSQL uuid-ossp extension. Add .HasPostgresExtension(""uuid-ossp"") to your context's OnModelCreating."); } } } diff --git a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/Internal/NpgsqlMigrationsModelDiffer.cs b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/Internal/NpgsqlMigrationsModelDiffer.cs new file mode 100644 index 00000000..5950702a --- /dev/null +++ b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/Internal/NpgsqlMigrationsModelDiffer.cs @@ -0,0 +1,104 @@ +#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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Microsoft.EntityFrameworkCore.Storage; + +namespace Microsoft.EntityFrameworkCore.Migrations.Internal +{ + public class NpgsqlMigrationsModelDiffer : MigrationsModelDiffer + { + public NpgsqlMigrationsModelDiffer([NotNull] IRelationalTypeMapper typeMapper, [NotNull] IRelationalAnnotationProvider annotations, [NotNull] IMigrationsAnnotationProvider migrationsAnnotations) + : base(typeMapper, annotations, migrationsAnnotations) + {} + + protected override IReadOnlyList Sort( + [NotNull] IEnumerable operations, + [NotNull] DiffContext diffContext) + { + var ops = base.Sort(operations, diffContext); + + // base.Sort will leave operations it doesn't recognize (Npgsql-specific) + // at the end, go get these + if (ops.Count > 0 && !ops[ops.Count - 1].IsNpgsqlSpecific()) + return ops; + + var newOps = new List(); + newOps.AddRange(ops.SkipWhile(o => !o.IsNpgsqlSpecific())); + newOps.AddRange(ops.TakeWhile(o => !o.IsNpgsqlSpecific())); + return newOps; + } + + protected override IEnumerable Diff( + [CanBeNull] IModel source, + [CanBeNull] IModel target, + [NotNull] DiffContext diffContext) + => ( + source != null && target != null + ? Diff(source.Npgsql().PostgresExtensions, target.Npgsql().PostgresExtensions) + : source == null + ? target.Npgsql().PostgresExtensions.SelectMany(Add) + : source.Npgsql().PostgresExtensions.SelectMany(Remove) + ).Concat(base.Diff(source, target, diffContext)); + + protected virtual IEnumerable Diff( + [NotNull] IEnumerable source, + [NotNull] IEnumerable target) + => DiffCollection( + source, target, + Diff, Add, Remove, + (s, t) => s.Name == t.Name); + + protected virtual IEnumerable Diff([NotNull] IPostgresExtension source, [NotNull] IPostgresExtension target) + => Enumerable.Empty(); + + protected virtual IEnumerable Add([NotNull] IPostgresExtension target) + { + yield return new NpgsqlCreatePostgresExtensionOperation + { + Schema = target.Schema, + Name = target.Name, + Version = target.Version + }; + } + + protected virtual IEnumerable Remove([NotNull] IPostgresExtension source) + { + yield return new NpgsqlDropPostgresExtensionOperation { Name = source.Name }; + } + } + + static class MigrationOperationExtensions + { + internal static bool IsNpgsqlSpecific(this MigrationOperation op) + => op is NpgsqlCreatePostgresExtensionOperation || + op is NpgsqlDropPostgresExtensionOperation; + } +} diff --git a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/NpgsqlMigrationsSqlGenerator.cs index 213d20ba..c2320c15 100644 --- a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -341,6 +341,8 @@ public virtual void Generate(NpgsqlDropDatabaseOperation operation, IModel model .Append(dbName); } + #region PostgreSQL extensions + public virtual void Generate(NpgsqlCreatePostgresExtensionOperation operation, IModel model, RelationalCommandListBuilder builder) { Check.NotNull(operation, nameof(operation)); @@ -365,6 +367,18 @@ public virtual void Generate(NpgsqlCreatePostgresExtensionOperation operation, I } } + public virtual void Generate(NpgsqlDropPostgresExtensionOperation operation, IModel model, RelationalCommandListBuilder builder) + { + Check.NotNull(operation, nameof(operation)); + Check.NotNull(builder, nameof(builder)); + + builder + .Append("DROP EXTENSION ") + .Append(SqlGenerationHelper.DelimitIdentifier(operation.Name)); + } + + #endregion PostgreSQL extensions + protected override void Generate(DropIndexOperation operation, IModel model, RelationalCommandListBuilder builder) { Check.NotNull(operation, nameof(operation)); diff --git a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/Operations/NpgsqlDropPostgresExtensionOperation.cs b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/Operations/NpgsqlDropPostgresExtensionOperation.cs new file mode 100644 index 00000000..cf9a1f69 --- /dev/null +++ b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Migrations/Operations/NpgsqlDropPostgresExtensionOperation.cs @@ -0,0 +1,32 @@ +#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 JetBrains.Annotations; + +namespace Microsoft.EntityFrameworkCore.Migrations.Operations +{ + public class NpgsqlDropPostgresExtensionOperation : MigrationOperation + { + public virtual string Name { get; [param: NotNull] set; } + } +} diff --git a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Npgsql.EntityFrameworkCore.PostgreSQL.csproj b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Npgsql.EntityFrameworkCore.PostgreSQL.csproj index 449de552..cd8ff056 100644 --- a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Npgsql.EntityFrameworkCore.PostgreSQL.csproj +++ b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Npgsql.EntityFrameworkCore.PostgreSQL.csproj @@ -70,12 +70,14 @@ + + diff --git a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Storage/Internal/NpgsqlDatabaseCreator.cs b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Storage/Internal/NpgsqlDatabaseCreator.cs index a1b31edc..c75d6b72 100644 --- a/src/Npgsql.EntityFrameworkCore.PostgreSQL/Storage/Internal/NpgsqlDatabaseCreator.cs +++ b/src/Npgsql.EntityFrameworkCore.PostgreSQL/Storage/Internal/NpgsqlDatabaseCreator.cs @@ -21,13 +21,16 @@ // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #endregion +using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations.Internal; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Utilities; using Npgsql; @@ -36,9 +39,10 @@ namespace Microsoft.EntityFrameworkCore.Storage.Internal { public class NpgsqlDatabaseCreator : RelationalDatabaseCreator { - private readonly NpgsqlRelationalConnection _connection; - private readonly IMigrationsSqlGenerator _migrationsSqlGenerator; - private readonly IRawSqlCommandBuilder _rawSqlCommandBuilder; + readonly NpgsqlRelationalConnection _connection; + readonly IMigrationsSqlGenerator _migrationsSqlGenerator; + readonly IRawSqlCommandBuilder _rawSqlCommandBuilder; + readonly IMigrationsModelDiffer _modelDiffer; public NpgsqlDatabaseCreator( [NotNull] NpgsqlRelationalConnection connection, @@ -51,6 +55,7 @@ public class NpgsqlDatabaseCreator : RelationalDatabaseCreator Check.NotNull(rawSqlCommandBuilder, nameof(rawSqlCommandBuilder)); _connection = connection; + _modelDiffer = modelDiffer; _migrationsSqlGenerator = migrationsSqlGenerator; _rawSqlCommandBuilder = rawSqlCommandBuilder; } @@ -63,24 +68,6 @@ public override void Create() ClearPool(); } - - var postCreateOperations = CreatePostCreateOperations(); - postCreateOperations.ExecuteNonQuery(_connection); - - if (postCreateOperations.Any()) - { - // The post-creation operations may have create new types (e.g. extension), - // reload type definitions - _connection.Open(); - try - { - ((NpgsqlConnection)_connection.DbConnection).ReloadTypes(); - } - finally - { - _connection.Close(); - } - } } public override async Task CreateAsync(CancellationToken cancellationToken = default(CancellationToken)) @@ -91,25 +78,6 @@ public override async Task CreateAsync(CancellationToken cancellationToken = def ClearPool(); } - - var postCreateOperations = CreatePostCreateOperations(); - await postCreateOperations.ExecuteNonQueryAsync(_connection); - - if (postCreateOperations.Any()) - { - // The post-creation operations may have create new types (e.g. extension), - // reload type definitions - _connection.Open(); - try - { - // TODO: This is a non-async operation... - ((NpgsqlConnection)_connection.DbConnection).ReloadTypes(); - } - finally - { - _connection.Close(); - } - } } protected override bool HasTables() @@ -129,23 +97,6 @@ FROM information_schema.tables IEnumerable CreateCreateOperations() => _migrationsSqlGenerator.Generate(new[] { new NpgsqlCreateDatabaseOperation { Name = _connection.DbConnection.Database, Template = Model.Npgsql().DatabaseTemplate } }); - /// - /// Creates migration operations that should take place immediately after creating the database, - /// e.g. PostgreSQL extension setup - /// - List CreatePostCreateOperations() - { - var operations = new List(); - foreach (var extension in Model.Npgsql().PostgresExtensions) - operations.Add(new NpgsqlCreatePostgresExtensionOperation - { - Name = extension.Name, - Schema = extension.Schema, - Version = extension.Version - }); - return _migrationsSqlGenerator.Generate(operations).ToList(); - } - public override bool Exists() { try @@ -185,7 +136,7 @@ public override async Task ExistsAsync(CancellationToken cancellationToken } // Login failed is thrown when database does not exist (See Issue #776) - private static bool IsDoesNotExist(PostgresException exception) => exception.SqlState == "3D000"; + static bool IsDoesNotExist(PostgresException exception) => exception.SqlState == "3D000"; public override void Delete() { @@ -207,7 +158,56 @@ public override async Task DeleteAsync(CancellationToken cancellationToken = def } } - private IEnumerable CreateDropCommands() + public override void CreateTables() + { + var operations = _modelDiffer.GetDifferences(null, Model); + var commands = _migrationsSqlGenerator.Generate(operations, Model); + + // Adding a PostgreSQL extension might define new types (e.g. hstore), which we + // Npgsql to reload + var reloadTypes = operations.Any(o => o is NpgsqlCreatePostgresExtensionOperation); + + using (var transaction = Connection.BeginTransaction()) + { + commands.ExecuteNonQuery(Connection); + + transaction.Commit(); + } + + if (reloadTypes) + { + var npgsqlConn = (NpgsqlConnection)Connection.DbConnection; + if (npgsqlConn.FullState == ConnectionState.Open) + npgsqlConn.ReloadTypes(); + } + } + + public override async Task CreateTablesAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var operations = _modelDiffer.GetDifferences(null, Model); + var commands = _migrationsSqlGenerator.Generate(operations, Model); + + // Adding a PostgreSQL extension might define new types (e.g. hstore), which we + // Npgsql to reload + var reloadTypes = operations.Any(o => o is NpgsqlCreatePostgresExtensionOperation); + + using (var transaction = await Connection.BeginTransactionAsync(cancellationToken)) + { + await commands.ExecuteNonQueryAsync(Connection, cancellationToken); + + transaction.Commit(); + } + + // TODO: Not async + if (reloadTypes) + { + var npgsqlConn = (NpgsqlConnection)Connection.DbConnection; + if (npgsqlConn.FullState == ConnectionState.Open) + npgsqlConn.ReloadTypes(); + } + } + + IEnumerable CreateDropCommands() { var operations = new MigrationOperation[] { diff --git a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/BatchingTest.cs b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/BatchingTest.cs index 31af3f37..da68a625 100644 --- a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/BatchingTest.cs +++ b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/BatchingTest.cs @@ -92,6 +92,8 @@ public BloggingContext(IServiceProvider serviceProvider, DbContextOptions option protected override void OnModelCreating(ModelBuilder modelBuilder) { + modelBuilder.HasPostgresExtension("uuid-ossp"); + modelBuilder.Entity(b => { //b.Property(e => e.Id).HasDefaultValueSql("NEWID()"); diff --git a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/BuiltInDataTypesNpgsqlFixture.cs b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/BuiltInDataTypesNpgsqlFixture.cs index d89b16db..b3d42e8e 100644 --- a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/BuiltInDataTypesNpgsqlFixture.cs +++ b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/BuiltInDataTypesNpgsqlFixture.cs @@ -28,41 +28,20 @@ public BuiltInDataTypesNpgsqlFixture() { _testStore = NpgsqlTestStore.CreateScratch(); - /* - // TODO: find a better way to do this - _testStore.ExecuteNonQuery("CREATE TYPE some_composite AS (some_number int, some_text text)"); - var npgsqlConn = (NpgsqlConnection)_testStore.Connection; - npgsqlConn.ReloadTypes(); - npgsqlConn.MapComposite(); - */ - var serviceProvider = new ServiceCollection() .AddEntityFrameworkNpgsql() .AddSingleton(TestNpgsqlModelSource.GetFactory(OnModelCreating)) .BuildServiceProvider(); - // We need the database to be created with NpgsqlDatabaseCreator for the - // extension migration operations to take place. Drop the database created - // above by NpgsqlTestStore and recreate. - var tempOptions = new DbContextOptionsBuilder() - .UseNpgsql(_testStore.Connection) - .UseInternalServiceProvider(serviceProvider) - .Options; - - // Close the test store's connection because the database is about to - // get dropped (via a different master connection) - _testStore.Connection.Close(); - - using (var context = new DbContext(tempOptions)) - context.Database.EnsureDeleted(); - _options = new DbContextOptionsBuilder() - .UseNpgsql(_testStore.ConnectionString) + .UseNpgsql(_testStore.Connection) .UseInternalServiceProvider(serviceProvider) .Options; using (var context = new DbContext(_options)) + { context.Database.EnsureCreated(); + } } public override DbContext CreateContext() diff --git a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/GearsOfWarQueryNpgsqlFixture.cs b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/GearsOfWarQueryNpgsqlFixture.cs index 5559c91c..66d41948 100644 --- a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/GearsOfWarQueryNpgsqlFixture.cs +++ b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/GearsOfWarQueryNpgsqlFixture.cs @@ -8,6 +8,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Specification.Tests; using Microsoft.EntityFrameworkCore.Specification.Tests.TestModels.GearsOfWarModel; +using Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests.TestModels; using Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests.Utilities; namespace Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests @@ -68,5 +69,12 @@ public override GearsOfWarContext CreateContext(NpgsqlTestStore testStore) return context; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.HasPostgresExtension("uuid-ossp"); + + base.OnModelCreating(modelBuilder); + } } } diff --git a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/GraphUpdatesNpgsqlTest.cs b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/GraphUpdatesNpgsqlTest.cs index 7990d57a..e4575e70 100644 --- a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/GraphUpdatesNpgsqlTest.cs +++ b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/GraphUpdatesNpgsqlTest.cs @@ -32,6 +32,13 @@ public GraphUpdatesNpgsqlFixture() .BuildServiceProvider(); } + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.HasPostgresExtension("uuid-ossp"); + + base.OnModelCreating(modelBuilder); + } + public override NpgsqlTestStore CreateTestStore() { return NpgsqlTestStore.GetOrCreateShared(DatabaseName, () => diff --git a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/NpgsqlDatabaseCreatorTest.cs b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/NpgsqlDatabaseCreatorTest.cs index 209a985e..30fc5569 100644 --- a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/NpgsqlDatabaseCreatorTest.cs +++ b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/NpgsqlDatabaseCreatorTest.cs @@ -22,7 +22,8 @@ public void Postgres_extension_is_created() using (var context = new ExtensionContext(connString)) { var creator = context.GetService(); - creator.Create(); + creator.EnsureDeleted(); + creator.EnsureCreated(); try { diff --git a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/NpgsqlValueGenerationScenariosTest.cs b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/NpgsqlValueGenerationScenariosTest.cs index 10352b3b..10f475d2 100644 --- a/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/NpgsqlValueGenerationScenariosTest.cs +++ b/test/Npgsql.EntityFrameworkCore.PostgreSQL.FunctionalTests/NpgsqlValueGenerationScenariosTest.cs @@ -64,6 +64,8 @@ public class BlogContext : ContextBase { protected override void OnModelCreating(ModelBuilder modelBuilder) { + base.OnModelCreating(modelBuilder); + modelBuilder .Entity() .Property(e => e.Id) @@ -98,6 +100,8 @@ public class BlogContext : ContextBase { protected override void OnModelCreating(ModelBuilder modelBuilder) { + base.OnModelCreating(modelBuilder); + modelBuilder .Entity() .Property(e => e.OtherId) @@ -132,7 +136,7 @@ public class BlogContext : ContextBase { protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder.HasPostgresExtension("uuid-ossp"); + base.OnModelCreating(modelBuilder); modelBuilder .Entity() @@ -196,6 +200,11 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) var name = GetType().FullName.Substring((GetType().Namespace + nameof(NpgsqlValueGenerationScenariosTest)).Length + 2); optionsBuilder.UseNpgsql(NpgsqlTestStore.CreateConnectionString(name)); } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.HasPostgresExtension("uuid-ossp"); + } } public class TestBase -- GitLab