asp.net core - .NET, Entity Framework, C#: cannot insert explicit value for identity column - Stack Overflow

admin2025-04-19  1

I'm just trying to add a table ProcessingFlags to my database (mapped to a corresponding JobRunning class), and for some reason, when one record is about to be inserted in the table, the exception shown further down is thrown.

DbContext:

modelBuilder.Entity("UserManager.Data.Model.JobRunning", b =>
{
    b.Property<int>("Id")
        .HasColumnType("int");

    b.Property<bool>("IsProcessing")
        .HasColumnType("bit")
        .HasComment("Job is processing");

    b.HasKey("Id");

    b.ToTable("ProcessingFlags", null, t =>
    {
        t.HasComment("Semaphore to know if some process are executed and avoid the execution of others");
    });
});

ProcessingFlagsConfiguration:

public override void Configure(EntityTypeBuilder<JobRunning> builder)
{
    builder.ToTable(
        "ProcessingFlags",
        t => t.HasComment("Semaphore to know if some process are executed and avoid the execution of others")
    );

    builder.HasKey(k => k.Id);

    builder.Property(k => k.Id).ValueGeneratedOnAdd();
    builder.Property(p => p.IsProcessing).HasComment("Job is processing");
}

Migration:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateTable(
        name: "ProcessingFlags",
        columns: table => new
        {
            Id = table.Column<int>(type: "int", nullable: false)
                .Annotation("SqlServer:Identity", "1, 1"),
            IsProcessing = table.Column<bool>(type: "bit", nullable: false, comment: "Job is processing")
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_ProcessingFlags", x => x.Id);
        },
        comment: "Semaphore to know if some process are executed and avoid the execution of others");
}

Migration designer:

protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
    modelBuilder.Entity("Usage.Model.ProcessingFlags", b =>
    {
        b.Property<int>("Id")
            .HasColumnType("int")
            .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

        b.Property<int>("IsProcessing")
            .HasColumnType("bit")
            .HasComment("Job is processing");

        b.HasKey("Id");

        b.ToTable("ProcessingFlags");

        b.HasComment("Semaphore to know if some process are executed and avoid the execution of others");
    });
}

JobRunning class:

public sealed class JobRunning : Entity<JobRunningValues>, IJobRunning<JobRunningValues>
{
    public bool IsProcessing { get; set; }
}

JobRunningValues:

public enum JobRunningValues
{
    UserCleanup = 1
}

Running the migrations with Update-Database, the table is created correctly, but when trying to insert data, it throws the following exception:

Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot insert explicit value for identity column in table 'ProcessingFlags' when IDENTITY_INSERT is set to OFF.

I cannot touch the code where the record is to be inserted, because it belongs to an external nuget library we import in many projects and it's working, but I'll paste the code as a reference.

Code where the record is to be inserted:

public async ValueTask<bool> HandleAsync(UserCleanUpCommand request, CancellationToken ct = default)
{
    await using var _ = await JobProcess<JobRunning, JobRunningValues>.BeginAsync(
                async ct => await InternalHandleAsync(request, ct),
                _gen,
                _unitOfWork,
                _processingFlagsRepository,
                _sysLock,
                _eventBus,
                JobRunningValues.UserCleanup,
                request.JobId,
                _logger,
                request.Props.CorrelationId,
                ct
            );

    return true;
}

BeginAsync:

public static Task<IAsyncDisposable> BeginAsync(Func<CancellationToken, Task<(long Records, string? Note)>> action, IVdcIdGenerator gen, IVdcUnitOfWork unitOfWork, IVdcRepository<TJobRunning> jobRunningRepository, ISysLock sysLock, IEventBus eventBus, TJobCategory category, int? jobId, ILogger logger, string? correlationId, CancellationToken ct = default(CancellationToken))
{
    return new JobProcess<TJobRunning, TJobCategory>(category.ToString(), gen, sysLock, unitOfWork, jobRunningRepository, eventBus, category, jobId, correlationId, logger).StartAsync(action, ct);
}

StartAsync:

private async Task<IAsyncDisposable> StartAsync(Func<CancellationToken, Task<(long Records, string? Note)>> action, CancellationToken ct)
{
    _ = 5;
    try
    {
        int? jobId = _jobId;
        if (jobId.HasValue)
        {
            JobWorkerStartV0Event.B body = new JobWorkerStartV0Event.B(_jobId.Value, _gen.WorkerId);
            await _eventBus.PublishJobManagerEventAsync<JobWorkerStartV0Event, JobWorkerStartV0Event.B>(new JobWorkerStartV0Event(_gen.GenerateId(), new Guid(_jobId.Value, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), _gen.WorkerId, _correlationId, body), ct);
        }

        await using (await _sysLock.AcquireAsync(_lockName, null, ct))
        {
            var anon = await (from s in _jobRunningRepository.Find((TJobRunning x) => x.Id.Equals(_category))
                              select new { s.IsProcessing }).FirstOrDefaultAsync(ct);
            await FlagAsProcessingAsync(anon != null, anon?.IsProcessing ?? false, ct);
        }

        (long, string) tuple = await action(ct);
        long? records = tuple.Item1;
        _records = records;
        _note = tuple.Item2;
    }
    catch (Exception err)
    {
        LoggerExtensions.LogError(exception: _err = err, logger: _logger, message: "Error in processing", args: Array.Empty<object>());
    }

    return this;
}

FlagAsProcessingAsync:

private async Task FlagAsProcessingAsync(bool exist, bool isProcessing, CancellationToken ct)
{
    if (exist)
    {
        if (isProcessing)
        {
            throw new InvalidOperationException("There is other job in process.");
        }

        await _jobRunningRepository.Find((TJobRunning x) => x.Id.Equals(_category)).ExecuteUpdateAsync((SetPropertyCalls<TJobRunning> x) => x.SetProperty((TJobRunning p) => p.IsProcessing, valueExpression: true), ct);
    }
    else
    {
        TJobRunning entity = new TJobRunning
        {
            Id = _category,
            IsProcessing = true
        };
        await _jobRunningRepository.AddAsync(entity, ct);
        await _unitOfWork.SaveChangesAsync(ct);
    }
}

Again, I've paste the code starting from HandleAsync just as reference, because from the BeginAsync the code belongs to a library, so the problem must surely be in the migration / table creation, but cannot figure out what.

In the ProcessingFlagsConfiguration, I've already tried with ValueGeneratedNever (which I already know it wouldn't work), with ValueGeneratedOnAdd (which it should work) and just removing it, all to no avail, because as soon as it enters the BeginAsync method the error is thrown and the InternalHandlerAsync in never hit.

The .NET version is 8.

Edit 1: Adding SQL Create Table script for ProcessingFlags.

CREATE TABLE [dbo].[ProcessingFlags](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [IsProcessing] [bit] NOT NULL,
 CONSTRAINT [PK_ProcessingFlags] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

Edit 2:

Now I know (from one of my companions) that it is me the responsible of writing the Id field to table, so I'm even more confused now, because the Id field is set to Identity (1,1) in that table.

I'm just trying to add a table ProcessingFlags to my database (mapped to a corresponding JobRunning class), and for some reason, when one record is about to be inserted in the table, the exception shown further down is thrown.

DbContext:

modelBuilder.Entity("UserManager.Data.Model.JobRunning", b =>
{
    b.Property<int>("Id")
        .HasColumnType("int");

    b.Property<bool>("IsProcessing")
        .HasColumnType("bit")
        .HasComment("Job is processing");

    b.HasKey("Id");

    b.ToTable("ProcessingFlags", null, t =>
    {
        t.HasComment("Semaphore to know if some process are executed and avoid the execution of others");
    });
});

ProcessingFlagsConfiguration:

public override void Configure(EntityTypeBuilder<JobRunning> builder)
{
    builder.ToTable(
        "ProcessingFlags",
        t => t.HasComment("Semaphore to know if some process are executed and avoid the execution of others")
    );

    builder.HasKey(k => k.Id);

    builder.Property(k => k.Id).ValueGeneratedOnAdd();
    builder.Property(p => p.IsProcessing).HasComment("Job is processing");
}

Migration:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateTable(
        name: "ProcessingFlags",
        columns: table => new
        {
            Id = table.Column<int>(type: "int", nullable: false)
                .Annotation("SqlServer:Identity", "1, 1"),
            IsProcessing = table.Column<bool>(type: "bit", nullable: false, comment: "Job is processing")
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_ProcessingFlags", x => x.Id);
        },
        comment: "Semaphore to know if some process are executed and avoid the execution of others");
}

Migration designer:

protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
    modelBuilder.Entity("Usage.Model.ProcessingFlags", b =>
    {
        b.Property<int>("Id")
            .HasColumnType("int")
            .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

        b.Property<int>("IsProcessing")
            .HasColumnType("bit")
            .HasComment("Job is processing");

        b.HasKey("Id");

        b.ToTable("ProcessingFlags");

        b.HasComment("Semaphore to know if some process are executed and avoid the execution of others");
    });
}

JobRunning class:

public sealed class JobRunning : Entity<JobRunningValues>, IJobRunning<JobRunningValues>
{
    public bool IsProcessing { get; set; }
}

JobRunningValues:

public enum JobRunningValues
{
    UserCleanup = 1
}

Running the migrations with Update-Database, the table is created correctly, but when trying to insert data, it throws the following exception:

Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot insert explicit value for identity column in table 'ProcessingFlags' when IDENTITY_INSERT is set to OFF.

I cannot touch the code where the record is to be inserted, because it belongs to an external nuget library we import in many projects and it's working, but I'll paste the code as a reference.

Code where the record is to be inserted:

public async ValueTask<bool> HandleAsync(UserCleanUpCommand request, CancellationToken ct = default)
{
    await using var _ = await JobProcess<JobRunning, JobRunningValues>.BeginAsync(
                async ct => await InternalHandleAsync(request, ct),
                _gen,
                _unitOfWork,
                _processingFlagsRepository,
                _sysLock,
                _eventBus,
                JobRunningValues.UserCleanup,
                request.JobId,
                _logger,
                request.Props.CorrelationId,
                ct
            );

    return true;
}

BeginAsync:

public static Task<IAsyncDisposable> BeginAsync(Func<CancellationToken, Task<(long Records, string? Note)>> action, IVdcIdGenerator gen, IVdcUnitOfWork unitOfWork, IVdcRepository<TJobRunning> jobRunningRepository, ISysLock sysLock, IEventBus eventBus, TJobCategory category, int? jobId, ILogger logger, string? correlationId, CancellationToken ct = default(CancellationToken))
{
    return new JobProcess<TJobRunning, TJobCategory>(category.ToString(), gen, sysLock, unitOfWork, jobRunningRepository, eventBus, category, jobId, correlationId, logger).StartAsync(action, ct);
}

StartAsync:

private async Task<IAsyncDisposable> StartAsync(Func<CancellationToken, Task<(long Records, string? Note)>> action, CancellationToken ct)
{
    _ = 5;
    try
    {
        int? jobId = _jobId;
        if (jobId.HasValue)
        {
            JobWorkerStartV0Event.B body = new JobWorkerStartV0Event.B(_jobId.Value, _gen.WorkerId);
            await _eventBus.PublishJobManagerEventAsync<JobWorkerStartV0Event, JobWorkerStartV0Event.B>(new JobWorkerStartV0Event(_gen.GenerateId(), new Guid(_jobId.Value, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), _gen.WorkerId, _correlationId, body), ct);
        }

        await using (await _sysLock.AcquireAsync(_lockName, null, ct))
        {
            var anon = await (from s in _jobRunningRepository.Find((TJobRunning x) => x.Id.Equals(_category))
                              select new { s.IsProcessing }).FirstOrDefaultAsync(ct);
            await FlagAsProcessingAsync(anon != null, anon?.IsProcessing ?? false, ct);
        }

        (long, string) tuple = await action(ct);
        long? records = tuple.Item1;
        _records = records;
        _note = tuple.Item2;
    }
    catch (Exception err)
    {
        LoggerExtensions.LogError(exception: _err = err, logger: _logger, message: "Error in processing", args: Array.Empty<object>());
    }

    return this;
}

FlagAsProcessingAsync:

private async Task FlagAsProcessingAsync(bool exist, bool isProcessing, CancellationToken ct)
{
    if (exist)
    {
        if (isProcessing)
        {
            throw new InvalidOperationException("There is other job in process.");
        }

        await _jobRunningRepository.Find((TJobRunning x) => x.Id.Equals(_category)).ExecuteUpdateAsync((SetPropertyCalls<TJobRunning> x) => x.SetProperty((TJobRunning p) => p.IsProcessing, valueExpression: true), ct);
    }
    else
    {
        TJobRunning entity = new TJobRunning
        {
            Id = _category,
            IsProcessing = true
        };
        await _jobRunningRepository.AddAsync(entity, ct);
        await _unitOfWork.SaveChangesAsync(ct);
    }
}

Again, I've paste the code starting from HandleAsync just as reference, because from the BeginAsync the code belongs to a library, so the problem must surely be in the migration / table creation, but cannot figure out what.

In the ProcessingFlagsConfiguration, I've already tried with ValueGeneratedNever (which I already know it wouldn't work), with ValueGeneratedOnAdd (which it should work) and just removing it, all to no avail, because as soon as it enters the BeginAsync method the error is thrown and the InternalHandlerAsync in never hit.

The .NET version is 8.

Edit 1: Adding SQL Create Table script for ProcessingFlags.

CREATE TABLE [dbo].[ProcessingFlags](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [IsProcessing] [bit] NOT NULL,
 CONSTRAINT [PK_ProcessingFlags] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

Edit 2:

Now I know (from one of my companions) that it is me the responsible of writing the Id field to table, so I'm even more confused now, because the Id field is set to Identity (1,1) in that table.

Share Improve this question edited Mar 13 at 1:32 Zhi Lv 22k1 gold badge27 silver badges37 bronze badges asked Mar 5 at 16:13 Diego PerezDiego Perez 2,8843 gold badges39 silver badges86 bronze badges 6
  • 2 and it's EF Core and not Entity Framework 6 right? – Ivan Petrov Commented Mar 5 at 16:26
  • The error is caused by the line Id = _category. If JobRunning (i.e. its table) has an identity column, why do you (or they) assign an Id value to a new instance? – Gert Arnold Commented Mar 5 at 19:39
  • Side note: use Add, not AddAsync. You almost certainly don't need it. – Gert Arnold Commented Mar 5 at 19:52
  • @Ivan Petrov, correct. – Diego Perez Commented Mar 6 at 8:34
  • Thanks for your comment @Gert Arnold. I'm in a point where I'm not completely sure whether the insert should be handled by SQL or by our code. There is so much code I haven't created myself and its confusing, but whatever I do I get the same error. I removed the SqlServer:Identity annotation to no avail, I've also added ValueGeneratedNever in Configure, also tried removing the b.HasKey("Id") in the context, tried almost everything and always get the same exception. For the moment I don't care who inserts the Id field, as long as I can get rid of the exception. – Diego Perez Commented Mar 6 at 8:55
 |  Show 1 more comment

1 Answer 1

Reset to default 1

Based on the layout of your table, the IDENTITY flag is enabled. So SQL Server won't allow you to explicitly set a value for the corresponding column. If you can't remove the constraint from your SQL model, you have to disable temporarily the constraint.

So you need to enable the IDENTITY_INSERT per sql connection with the following sql statement :

SET IDENTITY_INSERT ProcessingFlags OFF;

A way to achieve that is to execute a raw SQL Query before the SaveChanges.

You can read official documentation about your issue here.

As you explained, a large part of the code shared is in a library you can't edit, but it looks like you can edit the HandleAsync method. If the unit of work pattern is commonly implemented, your _unitOfWork instance should hold a reference to your DbContext. So you need to figure a way to get the DbContext instance and execute something like that before BeginAsync:

dbContext.Database.ExecuteSqlRawAsync("SET IDENTITY_INSERT ProcessingFlags OFF;");
转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1745021539a280411.html

最新回复(0)