简体   繁体   中英

InsertAndGetIdAsync - Cannot insert explicit value for identity column

Using ASPNET Boilerplate (.NET Framework) 3.6.1

I have successfully used the AsyncCrudAppService on a number of entities without issue, but I've hit an issue with one particular entity type that I can't insert, as Entity Framework seems to think it's being provided an explicit ID.

My Entity:

public class Attendance : FullAuditedEntity<int>
{
    [Required]
    public Guid Guid { get; set; }

    public long? UserId { get; set; }
    [Required]
    public int EventId { get; set; }
    public int StatusId { get; set; }

    [Required]
    [MaxLength(100)]
    public string InviteEmail { get; set; }
    [Required]
    [MaxLength(20)]
    public string InviteCode { get; set; }

    public bool InviteAccepted { get; set; }

    public DateTime? InviteAcceptedDate { get; set; }

    public string InviteSource { get; set; }
    public long? InvitedByUserId { get; set; }

    [ForeignKey("UserId")]
    public User User { get; set; }
    [ForeignKey("InvitedByUserId")]
    public User InvitedByUser { get; set; }

    [ForeignKey("EventId")]
    public Event Event { get; set; }

    [ForeignKey("StatusId")]
    public AttendanceStatus Status { get; set; }
}

My CreateDto

[AutoMapTo(typeof(Attendance))]
public class CreateAttendanceDto
{
    public long? UserId { get; set; }
    [Required]
    public int EventId { get; set; }
    public int StatusId { get; set; }

    [Required]
    [MaxLength(100)]
    public string InviteEmail { get; set; }

    public bool InviteAccepted { get; set; }

    public DateTime? InviteAcceptedDate { get; set; }
    public string InviteSource { get; set; }
    public long? InvitedByUserId { get; set; }

}

My AppService Create method:

public override async Task<AttendanceDto> Create(CreateAttendanceDto input)
    {
        var attendance = ObjectMapper.Map<Attendance>(input);

        attendance.InviteCode = "TEST";

        // Create GUID
        attendance.Guid = Guid.NewGuid();

        await _attRepository.InsertAndGetIdAsync(attendance);
        return MapToEntityDto(attendance);
    }

Debugging the entity shows that is is sending id:0 to the insert method. This is exactly the same as another entity insert which is working fine.

Tracing the two different entity insert queries in SQL Profiler I can see that the working one has removed the ID from the insert query, where the one above that isn't working is trying to insert id=0 into the database, which is clearly a problem.

The error returned by the InsertAndGetIdAsync call as follows:

ERROR 2018-07-10 17:29:06,249 [108 ] nHandling.AbpApiExceptionFilterAttribute - An error occurred while updating the entries. See the inner exception for details. System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.Entity.Core.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Cannot insert explicit value for identity column in table 'Attendance' when IDENTITY_INSERT is set to OFF.

I've checked and double-checked for differences between these two appservice Creates and their related entities and dtos, and I can't find any differences. Even got a colleague to verify.

Any idea what might be going on here?

You need to specify a mapping for the entity Attendance so that it does not try to insert a value in the ID column. In simple terms, you need to makes EF aware that the ID column is configured for IDENTITY. The Exception message states this very clearly.

System.Data.SqlClient.SqlException: Cannot insert explicit value for identity column in table 'Attendance' when IDENTITY_INSERT is set to OFF.


Using attributes:

public class Attendance {
  [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  public long AttendanceId { get; set; }
}

or in fluent mapping in the DbContext type

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
  modelBuilder.Entity<Attendance>().Property(t => t.AttendanceId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}

I found the issue, which was a little hidden.

Inside my DbContext I had previously attempted to give the Guid field a default value (which I now realise was also making it an identity column in the eyes of EF). In the end this didn't work but I'd neglected to tidy it up:

        modelBuilder.Entity<Attendance>()
            .Property(x => x.Guid)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

The database did not have any identity column on the Guid column, and the error related to the Id column, but clearly this was confusing EF's handling of the id value in the resulting query.

Removed the above code, rebuilt and all is working as it should.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM