添加

时间:2017-09-20 18:14:21

标签: c# sql-server entity-framework asp.net-web-api entity-framework-6

我在通过DbContext.Add(...)方法添加新实体时遇到问题。在DbContext.SaveChanges()上,我得到一个DbUpdateConcurrencyException。我试图插入数据库。我是应用程序中唯一的开发人员,运行localhost,数据库表是原始的。没有用户。这只是我。

这并没有帮助,虽然它很相似:
Entity Framework 6 DbUpdateConcurrencyException When Adding New Rows To Database

我每次请求都使用一个DbContext。像这样:
One DbContext per request in ASP.NET MVC (without IOC container)

我正在注销实体框架生成的sql语句,如下所示:
https://stackoverflow.com/a/20751723/2088914

这是模型(代码优先,具有迁移)。当我发布时,我只提供了关联,角色,转让者和删除标志。行ID自动设置为0,因为我不是从客户端提供它,而date也是默认值,然后我在服务器上填充 - 所有预期的东西:

public class Permission {

    [Column("row_id")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int RowId { get; set; }

    [Key]
    [StringLength(10)]
    [Column("associate_nt_id", Order = 0)]
    [Required]
    public string AssociateNtId { get; set; }

    [Key]
    [Column("role_name", Order = 1)]
    [StringLength(50)]
    [Required]
    public string RoleName { get; set; }

    [Key]
    [Column("eff_ts", Order = 2)]
    [Required]
    public DateTime EffectiveTimestamp { get; set; }

    [StringLength(10)]
    [Column("assignor_nt_id")]
    [Required]
    public string RoleAssignorNtId { get; set; }

    [Column("deleted")]
    [Required]
    public bool Deleted { get; set; }

}

我有一个带有post方法的web api控制器,可以通过角度spa成功访问,并填充模型:

[HttpPost]
[Route("")]
[Require(Roles.admin)]
public Permission Post(Permission permission) {
    permission.EffectiveTimestamp = DateTime.Now;
    MAPDB.Current.Permissions.Add(permission);
    MAPDB.Current.Database.Log = s => {
        Debug.WriteLine(s); 
    };
    MAPDB.Current.SaveChanges();
    return permission;
}

我在visual studio 2015中运行调试。这里出现错误信息:
enter image description here

这是实体框架生成的sql:

INSERT [dbo].[_permissions]([associate_nt_id], [role_name], [eff_ts], [assignor_nt_id], [deleted]) 
VALUES (@0, @1, @2, @3, @4) 
SELECT [row_id] 
FROM [dbo].[_permissions] 
WHERE @@ROWCOUNT > 0 AND [associate_nt_id] = @0 AND [role_name] = @1 AND [eff_ts] = @2 
-- @0: 'associate' (Type = String, Size = 10)
-- @1: 'user' (Type = String, Size = 50) 
-- @2: '9/20/2017 12:49:05 PM' (Type = DateTime2)
-- @3: 'assignor' (Type = String, Size = 10)
-- @4: 'True' (Type = Boolean) 
-- Executing at 9/20/2017 12:49:05 PM -05:00
-- Completed in 24 ms with result: SqlDataReade
-- Closed connection at 9/20/2017 12:49:05 PM -05:00

它似乎已在logger中执行,并且该语句正是我所期望的,除了没有数据库插入。如果我从记录器中取出语句,填写参数,并通过sql客户端执行它,它可以工作并返回创建的行的id。我不明白问题是什么 - 没有并发情况发生,没有列丢失/添加不应该没有,没有无效参数,没有问题将列映射到对象属性,没有关键违规,身份栏没有问题。

如何让实体框架只插入这个新对象(不吞下异常)?

感谢您的帮助。

1 个答案:

答案 0 :(得分:4)

问题很可能是由PK的DateTime部分引起的(EffectiveTimestamp)。插入记录,但SELECT找不到它,因为默认情况下EF将DateTime属性映射到datetime列,而从日志中可以看到,参数类型是datetime2,它具有更高的精度,因此在存储到表列时会被截断,因此不会与选择过滤器的[eff_ts] = @2部分匹配。

要查看是否属于这种情况,您可以尝试修剪时间值:

// ...
var time = DateTime.Now;
permission.EffectiveTimestamp = new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second);
// ...

如果可行(正如我所料),您可以考虑更改数据库列类型:

[Key]
[Column("eff_ts", Order = 2, TypeName="datetime2")]
[Required]
public DateTime EffectiveTimestamp { get; set; }