Home > Blockchain >  Entity Framework Core 6 - Cannot insert explicit value for identity column in table 'Roles'
Entity Framework Core 6 - Cannot insert explicit value for identity column in table 'Roles'

Time:12-23

I currently have a problem with EF6 and Fluent API. When inserting into database where model have one to many relationship, I'm getting this error. I've checked some related topics, but I want to keep autoincrement. Model without one to many relationship works perfectly.

Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
 ---> Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot insert explicit value for identity column in table 'Roles' when IDENTITY_INSERT is set to OFF.
   at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__188_0(Task`1 result)
   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
ClientConnectionId:501a6880-e298-43d5-be69-fcbebacdb15e
Error Number:544,State:1,Class:16
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at WorkIT_Backend.Services.UserService.Create(String username, String password, String role) in C:\Users\Ondřej\Desktop\škola\2022 PRF\WS\OPR3\WorkIT_Backend\WorkIT_Backend\WorkIT_Backend\Services\UserService.cs:line 54
   at WorkIT_Backend.Controllers.UsersController.CreateUser(UserDto user) in C:\Users\Ondřej\Desktop\škola\2022 PRF\WS\OPR3\WorkIT_Backend\WorkIT_Backend\WorkIT_Backend\Controllers\UsersController.cs:line 57
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Model classes

public sealed class Role
{
    public long RoleId { get; set; }

    public string? Name { get; set; }

    public ICollection<User> Users { get; set; }

    public Role()
    {
        Users = new HashSet<User>();
    }
}
public class User
{
    public long UserId { get; set; }

    public string? UserName { get; set; }

    public string? PasswordHash { get; set; }
    public long RoleId { get; set; }

    public virtual Role Role { get; set; }

    public User()
    {
    }
}

OnModelCreating in dbcontext

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Role>(entity =>
        {
            entity.HasKey(q => q.RoleId);
            entity.Property(q => q.RoleId)
                .ValueGeneratedOnAdd();

            entity.Property(q => q.Name)
                .IsRequired();
            entity.HasIndex(q => q.Name)
                .IsUnique();
        });

        modelBuilder.Entity<User>(entity =>
        {
            entity.HasKey(q => q.UserId);
            entity.Property(q => q.UserId)
                .ValueGeneratedOnAdd();

            entity.Property(q => q.UserName)
                .IsRequired();

            entity.Property(q => q.PasswordHash)
                .IsRequired();

            entity.HasOne(u => u.Role)
                .WithMany(r => r.Users)
                .HasForeignKey(u => u.RoleId)
                .OnDelete(DeleteBehavior.ClientSetNull);
        });
    }

Method in service which is adding the user

public async Task<User> Create(string username, string password, string role)
    {
        EnsureNotNull(username, nameof(username));
        EnsureNotNull(password, nameof(password));
        EnsureNotNull(role, nameof(role));

        username = username.ToLower();

        if (_context.Users.Any(q => q.UserName == username))
            throw CreateException($"User {username} already exists.", null);

        var hash = _securityService.HashPassword(password);
        var userRole = await _roleService.GetRole(role);

        var ret = new User {UserName = username, PasswordHash = hash, Role = userRole};

        _context.Users.Add(ret);
        await _context.SaveChangesAsync();

        return ret;
    }

This method for adding roles works perfectly


public class RoleService
{
    private readonly WorkItDbContext _context;
    private readonly SecurityService _securityService;


    public RoleService(WorkItDbContext context, SecurityService securityService)
    {
        _context = context;
        _securityService = securityService;
    }

    public async Task<Role> Create(string name)
    {
        EnsureNotNull(name, nameof(name));

        name = name.ToLower();
        if (_context.Roles.Any(q => q.Name == name))
            throw CreateException($"Role {name} already exists.", null);

        var ret = new Role {Name = name};
        _context.Add(ret);
        await _context.SaveChangesAsync();
        return ret;
    }

    public async Task<List<Role>> GetRoles()
    {
        var roles = await _context.Roles.ToListAsync();
        return roles;
    }

    public async Task<Role> GetRole(string name)
    {
        var role = await _context.Roles.FirstAsync(q => q.Name == name) ??
                   throw CreateException($"Role {name} does not exist.");
        return role;
    }
}

Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
SecurityService securityService = new(builder.Configuration);
builder.Services.AddTransient<WorkItDbContext>();
builder.Services.AddSingleton<SecurityService>();
builder.Services.AddTransient<UserService>();
builder.Services.AddTransient<RoleService>();

I've different combination of dbcontext methods. I tried auto increment through anotation - identity. I've checked SQL server and autoincrement is alright.

CodePudding user response:

Change

builder.Services.AddTransient<WorkItDbContext>();

to

builder.Services.AddDbContext<WorkItDbContext>();

and then your UserService and RoleService will share a WorkItDbContext, because it will be added as a Scoped service. See DbContext in dependency injection for ASP.NET Core

  • Related