efcore.pg icon indicating copy to clipboard operation
efcore.pg copied to clipboard

7.0.11 gives `__EFMigrationsHistory already exists` on `dbContext.Database.Migrate();`

Open TDroogers opened this issue 2 years ago • 15 comments

After updating from 7.0.4 to 7.0.11 I get the error: Npgsql.PostgresException: '42P07: relation "__EFMigrationsHistory" already exists' on running dbContext.Database.Migrate(); from the program.cs in an winforms (core 7.0.11) application.

My connect string looks like this: "Host=localhost;Database=dev_copy;Username=postgres;Password=postgres; SearchPath = schema_prod"

After downgrading Npgsql back to 7.0.4 it works again as expected.

TDroogers avatar Sep 19 '23 06:09 TDroogers

Given the only change in 7.0.11 is #2787 and this is related to schema I suspect migrations on a different schema now always default to public and the default schema is not used in this development db.

TDroogers avatar Sep 19 '23 06:09 TDroogers

@roji Sorry to tag you, but have you seen this issue?

TDroogers avatar Sep 27 '23 08:09 TDroogers

Yes, but I'm currently busy with other urgent matters... I'll try to take a look at this as soon as I can.

roji avatar Sep 27 '23 11:09 roji

As a temporary workaround you can explicitly set the MigrationHistoryTable schema. We do something like this:

    var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString);
    var searchPaths = connectionStringBuilder.SearchPath?.Split(',');

    options.UseNpgsql(connectionString, o =>
        {
            configure(o);

            if (searchPaths is {Length: > 0})
            {
                var mainSchema = searchPaths[0];
                o.MigrationsHistoryTable(HistoryRepository.DefaultTableName, mainSchema);
            }
        })

It's not very elegant, but it works.

zlepper avatar Nov 10 '23 07:11 zlepper

Thanks @zlepper this works!

TDroogers avatar Nov 24 '23 13:11 TDroogers

Thanks @zlepper this helped me also in Npgsql Version 6.0.10 (Npgsql.EntityFrameworkCore.PostgreSQL Version 6.0.22).

Kaffeetasse avatar Nov 24 '23 14:11 Kaffeetasse

I am seeing the same issue with version 8.0.0

Here are the steps to reproduce this issue.

  1. Connect to the "postgres" database and execute this command to create a user.
CREATE ROLE mydbusr WITH
    LOGIN
    NOSUPERUSER
    NOCREATEDB
    NOCREATEROLE
    INHERIT
    NOREPLICATION
    CONNECTION LIMIT -1
    PASSWORD 'password';
  1. Then execute this command to create a database.
CREATE DATABASE "MyDb"
    WITH
    OWNER = postgres
    ENCODING = 'UTF8'
    CONNECTION LIMIT = -1
    IS_TEMPLATE = False;
  1. Connect to the "MyDb" database and execute this command to create a schema.
CREATE SCHEMA mydbusr AUTHORIZATION mydbusr;
  1. Create a class library project and add the EF Core packages.
dotnet new classlib -o EfCoreBug
cd EfCoreBug
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 8.0.0
dotnet add package Microsoft.EntityFrameworkCore.Design --version 8.0.0
  1. Copy/Paste this code into the class library project.
using Microsoft.EntityFrameworkCore;

namespace EfCoreBug;

public class MyContext : DbContext
{
    public DbSet<MyEntity> MyEntities { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseNpgsql("Host=localhost;Username=mydbusr;Password=password;Database=MyDb");
}

public class MyEntity
{
    public int Id { get; set; }
}
  1. Create the Entity Framework migration and update the database.
dotnet ef migrations add InitialCreate
dotnet ef database update
  1. Change the model.
using Microsoft.EntityFrameworkCore;

namespace EfCoreBug;

public class MyContext : DbContext
{
    public DbSet<MyEntity> MyEntities { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseNpgsql("Host=localhost;Username=mydbusr;Password=password;Database=MyDb");
}

public class MyEntity
{
    public int Id { get; set; }
+    public string? NewColumn { get; set; }
}
  1. Create a new migration.
dotnet ef migrations add AddNewColumn
  1. Try to apply the new migration.
dotnet ef database update

You should get the following error output.

Failed executing DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE "__EFMigrationsHistory" (
    "MigrationId" character varying(150) NOT NULL,
    "ProductVersion" character varying(32) NOT NULL,
    CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
);
Npgsql.PostgresException (0x80004005): 42P07: relation "__EFMigrationsHistory" already exists
   at Npgsql.Internal.NpgsqlConnector.ReadMessageLong(Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
   at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
   at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
   at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
   at Npgsql.NpgsqlDataReader.NextResult()
   at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteNonQuery(Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlCommand.ExecuteNonQuery()
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Internal.NpgsqlMigrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String connectionString, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String connectionString, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
  Exception data:
    Severity: ERROR
    SqlState: 42P07
    MessageText: relation "__EFMigrationsHistory" already exists
    File: heap.c
    Line: 1146
    Routine: heap_create_with_catalog
42P07: relation "__EFMigrationsHistory" already exists

bassem-mf avatar Dec 16 '23 05:12 bassem-mf

As a temporary workaround you can explicitly set the MigrationHistoryTable schema. We do something like this:

    var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString);
    var searchPaths = connectionStringBuilder.SearchPath?.Split(',');

    options.UseNpgsql(connectionString, o =>
        {
            configure(o);

            if (searchPaths is {Length: > 0})
            {
                var mainSchema = searchPaths[0];
                o.MigrationsHistoryTable(HistoryRepository.DefaultTableName, mainSchema);
            }
        })

It's not very elegant, but it works.

Thanks, just suffered this issue and added this code snippet to get around the issue. Only affects my databases where public isn't the main schema.

mcbainuk12 avatar Dec 20 '23 20:12 mcbainuk12

+1

ParadiseFallen avatar Dec 28 '23 13:12 ParadiseFallen

+1

VolkmarR avatar Feb 08 '24 17:02 VolkmarR

+1

ybda avatar Mar 15 '24 13:03 ybda

+1

xactlance avatar Apr 03 '24 23:04 xactlance

Everyone, please don't post +1 comments, upvote (👍) the top post instead.

roji avatar Apr 04 '24 16:04 roji

configure(o);

Thanks ! It's works !

But what is function configure ?

anhhtca avatar Apr 19 '24 10:04 anhhtca

Will this be fixed in a future release?

ArneRanvik avatar Aug 15 '24 10:08 ArneRanvik