InsertAndGetIdAsync-无法为身份列插入明确的值

时间:2018-07-10 16:46:50

标签: c# entity-framework aspnetboilerplate

使用ASPNET Boilerplate(.NET Framework)3.6.1

我已经成功地在许多实体上使用了AsyncCrudAppService,没有出现问题,但是我遇到了一个无法插入的特定实体类型的问题,因为Entity Framework似乎认为它已被提供了显式ID。< / p>

我的实体:

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; }
}

我的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; }

}

我的AppService创建方法:

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);
    }

调试实体表明正在向id方法发送id:0。这与可以正常工作的另一个实体插入完全相同。

在SQL事件探查器中跟踪两个不同的实体插入查询,我可以看到正常工作的一个已从插入查询中删除了ID,其中上面一个不起作用的实例正在尝试将id = 0插入数据库中,显然是个问题。

InsertAndGetIdAsync调用返回的错误如下:

  

错误2018-07-10 17:29:06,249 [108] nHandling.AbpApiExceptionFilterAttribute-更新条目时发生错误。有关详细信息,请参见内部异常。   System.Data.Entity.Infrastructure.DbUpdateException:更新条目时发生错误。有关详细信息,请参见内部异常。 ---> System.Data.Entity.Core.UpdateException:更新条目时发生错误。有关详细信息,请参见内部异常。 ---> System.Data.SqlClient.SqlException:当IDENTITY_INSERT设置为OFF时,无法为表'Attendance'中的Identity列插入显式值。

我已经检查并仔细检查了这两个appservice Creates及其相关实体和dto之间的差异,但找不到任何差异。甚至有一个同事来验证。

你知道这里会发生什么吗?

2 个答案:

答案 0 :(得分:2)

您需要为实体Attendance指定一个映射,以便它不会尝试在ID列中插入值。简而言之,您需要让EF知道ID列已配置为IDENTITY。异常消息清楚地表明了这一点。

  

System.Data.SqlClient.SqlException:当IDENTITY_INSERT设置为OFF时,无法为表'Attendance'中的Identity列插入显式值。


使用属性:

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

DbContext类型的流利映射中

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

答案 1 :(得分:0)

我发现了这个隐患。

在我的DbContext中,我以前曾尝试为Guid字段提供一个默认值(我现在意识到,这也使它成为EF的标识列)。最后这没有用,但我忽略了整理它:

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

数据库在Guid列上没有任何标识列,并且错误与Id列有关,但是很显然,这使EF在结果查询中对id值的处理变得混乱。

删除了上面的代码,对其进行了重新构建,一切都可以正常工作。