2

.NET Core 2.2 application with Npgsql EF Core 2.2.4, Npgsql Nodatime 2.2.4

I'm trying to bulk update records and Entity Framework is throwing an exception 42883: operator does not exist: information_schema.sql_identifier + unknown

If I don't use BulkUpdate and instead use

_dbContext.UpdateRange(data)
_dbContext.SaveChanges();

then everything is fine. But I was wondering why it is not working with _dbContext.BulkUpdate(data)?

The following is a sanitized version of what we're doing:

public void BulkUpdate(List<AutoAction> data)
{
    try
    {
        _dbContext.BulkUpdate(data);
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        throw;
    }
}

public class AutoAction
{
    public int Id { get; set; }
    public int SettingsId { get; set; }
    public Settings Setting { get; set; }
    public Type ActionType { get; set; }
    public LocalDate DateEffective { get; set; }
    public bool Processed { get; set; }
    public Instant CreatedDateUtc { get; set; }
    public Instant? ProcessedOnUtc { get; set; }
    public Status Status { get; set; }
}

DbContext.cs

public DbSet<AutoAction> AutoActions { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfiguration(new AutoActionConfiguration());
    base.OnModelCreating(modelBuilder);
}

AutoActionConfiguration.cs

public class AutoActionConfiguration : IEntityTypeConfiguration<AutoAction> 
{
    public void Configure(EntityTypeBuilder<AutoAction> builder)
    {
        builder.ToTable("AutoAction");
        builder.HasKey(x => x.Id);
        builder.Ignore(x => x.Setting);
        builder.Property(x => x.Id).ValueGeneratedOnAdd();
        builder.Property(a => a.Processed).HasColumnType("BOOLEAN");
        builder.Property(a => a.ProcessedOnUtc).HasColumnType("timestamp");
        builder.Property(a => a.CreatedDateUtc).HasColumnType("timestamp");
        builder.Property(a => a.DateEffective).HasColumnType("date");

        var actionTypeConverter = new EnumToNumberConverter<Type, int>();
        builder.Property(a => a.ActionType).HasConversion(actionTypeConverter).HasColumnName("ActionType");

        var statusTypeConverter = new EnumToNumberConverter<Status, int>();
        builder.Property(a => a.Status).HasConversion(statusTypeConverter).HasColumnName("Status");
    }
}

Startup.cs

services.AddDbContext<DbContext>((serviceProvider, options) =>
            {
                var factory = serviceProvider.GetRequiredService<IConnectionFactory>();

                var connection = factory.GetPostgresServerConnection();

                options.UseNpgsql(connection, optionsBuilder =>
                {
                    var coreOptionsBuilder = ((IRelationalDbContextOptionsBuilderInfrastructure)optionsBuilder).OptionsBuilder;

                    var extension = coreOptionsBuilder.Options.FindExtension<NpgsqlNodaTimeOptionsExtension>()
                                    ?? new NpgsqlNodaTimeOptionsExtension();

                    ((IDbContextOptionsBuilderInfrastructure)coreOptionsBuilder).AddOrUpdateExtension(extension);
                });
            });

Exception

hint: No operator matches the given name and argument types. You might need to add explicit type casts.

stacktrace: at Npgsql.NpgsqlConnector.<>c__DisplayClass161_0.<<ReadMessage>g__ReadMessageLong|0>d.MoveNext()
End of stack trace from previous location where exception was thrown ---
   at Npgsql.NpgsqlConnector.<>c__DisplayClass161_0.<<ReadMessage>g__ReadMessageLong|0>d.MoveNext() in C:\projects\npgsql\src\Npgsql\NpgsqlConnector.cs:line 1032
End of stack trace from previous location where exception was thrown ---
   at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming) in C:\projects\npgsql\src\Npgsql\NpgsqlDataReader.cs:line 446
   at Npgsql.NpgsqlDataReader.NextResult() in C:\projects\npgsql\src\Npgsql\NpgsqlDataReader.cs:line 332
   at Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior, Boolean async, CancellationToken cancellationToken) in C:\projects\npgsql\src\Npgsql\NpgsqlCommand.cs:line 1218
   at Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior) in C:\projects\npgsql\src\Npgsql\NpgsqlCommand.cs:line 1130
   at EFCore.BulkExtensions.TableInfo.CheckHasIdentity(DbContext context)
   at EFCore.BulkExtensions.SqlBulkOperation.Merge[T](DbContext context, IList`1 entities, TableInfo tableInfo, OperationType operationType, Action`1 progress)
   at EFCore.BulkExtensions.DbContextBulkExtensions.BulkUpdate[T](DbContext context, IList`1 entities, BulkConfig bulkConfig, Action`1 progress)

SQL: SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMNPROPERTY(object_id(TABLE_SCHEMA+'.'+TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1 and TABLE_NAME = 'autoaction' and TABLE_SCHEMA = 'dbo'
   42883: operator does not exist: information_schema.sql_identifier + unknown

Not sure where to add explicit type casts as it is mentioned as a hint from the exception.

BigUuice
  • 21
  • 7
  • Where is the BulkUpdate method coming from? As this isn't part of EF Core, I'm assuming it's a 3rd-party package which may or may not be compatible with PostgreSQL. Please include the full details, version, etc. – Shay Rojansky Dec 18 '19 at 16:28

1 Answers1

1

The way I ready that error it is trying to find a column with IDENTITY property in the table rateautoaction and can't.

It seems like this is a requirement for using this function.

The other part I don't understand is the SQL there shows the function COLUMNPROPERTY being called -- but that is only on SQL Server. But you say you are using PostgreSQL.

Are you using SQL Server library with Postgre? That would not be a good idea.

Hogan
  • 69,564
  • 10
  • 76
  • 117
  • Coming to the first part of your answer, I'm configuring the IDENTITY property in the configuration.cs file as `builder.HasKey(x => x.Id);` But for some reason is it not enough for using BulkUpdate? In the second part, the table is in PostgreSQL and the dbcontext is configured properly to use that table. However, in my application, we are also using a few tables which are in Microsoft SQL Server but it has its context and configuration. Do you think that SQL Server configuration is affecting here? – BigUuice Dec 11 '19 at 02:59
  • That function is only valid for SQL Server. – Hogan Dec 11 '19 at 14:00