Summary
UpsertAsync always tries to create a unique constraint even if it already exists in the target table.
Version
EFCore.BulkExtensions 10.0.1
EFCore.BulkExtensions.PostgreSql 10.0.1
Npgsql.EntityFrameworkCore.PostgreSQL 10.0.1
- .NET 10 / PostgreSQL 17
Reproduce
class Example
{
public int Id { get; set; }
public int OtherUniqueKey { get; set; }
}
var config = new BulkConfig { UpdateByProperties = new List<string> { nameof(Example.OtherUniqueKey) } };
await using var dbTransaction = await dbContext.Database.BeginTransactionAsync();
await dbContext.BulkInsertOrUpdateAsync(batch, config);
Fails with the error:
CREATE INDEX CONCURRENTLY cannot run inside a transaction block
because it tries to create a unique index inside the transaction on the OtherUniqueKey column, even though it already exists.
Root cause
In EFCore.BulkExtensions.PostgreSql/SqlAdapters/PostgreSql/PostgreSqlAdapter.cs, the ReconfigureTableInfo method has a signature with DbContext in its parameters:
public string? ReconfigureTableInfo(DbContext context, TableInfo tableInfo)
However, in the implemented interface, the parameter was changed to:
virtual string? ReconfigureTableInfo(BulkContext context, TableInfo tableInfo) { return null; }
Because of this type mismatch, the method in PostgreSqlAdapter does not override the interface method. As a result, the schema for the index search is not set, and the index is not found.
Expected behavior
The schema is set correctly inside TableInfo, the index is found, and there is no attempt to create a duplicate unique index.
Suggested fix
Replace DbContext with BulkContext in the ReconfigureTableInfo method signature inside EFCore.BulkExtensions.PostgreSql/SqlAdapters/PostgreSql/PostgreSqlAdapter.cs.
Summary
UpsertAsync always tries to create a unique constraint even if it already exists in the target table.
Version
EFCore.BulkExtensions10.0.1EFCore.BulkExtensions.PostgreSql10.0.1Npgsql.EntityFrameworkCore.PostgreSQL10.0.1Reproduce
Fails with the error:
CREATE INDEX CONCURRENTLY cannot run inside a transaction blockbecause it tries to create a unique index inside the transaction on the
OtherUniqueKeycolumn, even though it already exists.Root cause
In
EFCore.BulkExtensions.PostgreSql/SqlAdapters/PostgreSql/PostgreSqlAdapter.cs, theReconfigureTableInfomethod has a signature withDbContextin its parameters:However, in the implemented interface, the parameter was changed to:
Because of this type mismatch, the method in
PostgreSqlAdapterdoes not override the interface method. As a result, the schema for the index search is not set, and the index is not found.Expected behavior
The schema is set correctly inside
TableInfo, the index is found, and there is no attempt to create a duplicate unique index.Suggested fix
Replace
DbContextwithBulkContextin theReconfigureTableInfomethod signature insideEFCore.BulkExtensions.PostgreSql/SqlAdapters/PostgreSql/PostgreSqlAdapter.cs.