.Update() returns "Cannot update identity column"
.Update() returns "Cannot update identity column"
在索引型显示器上有一个 link 将控制指向下面的方法。凭证状态更新为 "Reconciled" 然后尝试保存。
一切似乎都按预期执行,直到 Update/Save 当我得到异常时,"Cannot update identity column."
Voucher 模型中没有导航属性。两个标识列都在插入时很好地填充。
模特在这里:
public class Voucher
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string VoucherId { get; set; }
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Int64 VoucherNumber { get; set; }
[Required]
public string StudentId { get; set; }
public string FullName { get; set; }
[Required]
public string VoucherType { get; set; }
[Required]
public DateTime VoucherCreateDate { get; set; }
[Required]
public string VoucherStatus { get; set; }
}
public ViewResult ReconcileVoucher(string id) //, Voucher voucher)
{
Voucher voucher = _context.Vouchers
.Single(m => m.VoucherId == id);
if (id != voucher.VoucherId)
{
ModelState.AddModelError("InputStatus", "Indicated Voucher is not present " + voucher.FullName);
return View();
}
voucher.VoucherStatus = "Reconciled";
if (ModelState.IsValid)
{
try
{
_context.Update(voucher);
_context.SaveChanges();
ModelState.AddModelError("InputStatus", "Voucher was Reconciled for " + voucher.FullName);
}
catch (DbUpdateConcurrencyException ex)
{
CreateLogRow("Reconcile Voucher", "testUser", "Concurrency exception for " + voucher.StudentId, ex.Message);
if (!VoucherExists(voucher.VoucherId))
{
ModelState.AddModelError("InputStatus", "The Voucher for " + voucher.FullName + " cannot be found");
return View();
}
else
{
throw;
}
}
CreateLogRow("Reconcile Voucher", "testUser", "Voucher was edited for " + voucher.StudentId + " - " + voucher.FullName, null);
return View();
}
return View(voucher);
}
您通过调用
将所有属性标记为已修改
_context.Update(voucher);
要么省略此调用并让更改跟踪器确定更新的列,要么明确将 VoucherNumber 属性 标记为未修改。
db.Update(voucher);
db.Entry(voucher).Property(nameof(Voucher.VoucherNumber)).IsModified = false;
当您在调用中从 DbContext 获取实体并更新 属性 时,您不应调用 Update
,而应仅调用 SaveChanges
.
即
Voucher voucher = _context.Vouchers
.Single(m => m.VoucherId == id);
// ...
voucher.VoucherStatus = "Reconciled";
// ...
_context.SaveChanges();
Update
将生成一个语句,该语句将更新实体上的 all 列,虽然这应该排除标记为 DatabaseGeneratedOption.Identity
的列,但这可能这里不是这种情况。通过让更改跟踪在没有 Update 调用的情况下执行其操作,EF 将仅为更改的列生成 UPDATE 语句。
Update
在接受一个实体(如您注释掉的那样)和 attaching/updating 其整体状态时会更适用。我不推荐这种方法,因为它会覆盖所有值并且容易受到许多问题的影响,包括陈旧的数据更新和来自客户端的意外篡改。 (通过 man-in-the-browser/middle 攻击修改您的 UI 不允许的列)最好加载新的实体,验证传入数据,检查行 versions/modified 时间戳是否有陈旧更新等,而不是接受一个面值的实体并将其推入数据库。
编辑:如果这些 ID 在数据库中是 GUID,那么为什么不将它们转换为实体中的 GUID?
在索引型显示器上有一个 link 将控制指向下面的方法。凭证状态更新为 "Reconciled" 然后尝试保存。
一切似乎都按预期执行,直到 Update/Save 当我得到异常时,"Cannot update identity column."
Voucher 模型中没有导航属性。两个标识列都在插入时很好地填充。
模特在这里:
public class Voucher
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string VoucherId { get; set; }
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Int64 VoucherNumber { get; set; }
[Required]
public string StudentId { get; set; }
public string FullName { get; set; }
[Required]
public string VoucherType { get; set; }
[Required]
public DateTime VoucherCreateDate { get; set; }
[Required]
public string VoucherStatus { get; set; }
}
public ViewResult ReconcileVoucher(string id) //, Voucher voucher)
{
Voucher voucher = _context.Vouchers
.Single(m => m.VoucherId == id);
if (id != voucher.VoucherId)
{
ModelState.AddModelError("InputStatus", "Indicated Voucher is not present " + voucher.FullName);
return View();
}
voucher.VoucherStatus = "Reconciled";
if (ModelState.IsValid)
{
try
{
_context.Update(voucher);
_context.SaveChanges();
ModelState.AddModelError("InputStatus", "Voucher was Reconciled for " + voucher.FullName);
}
catch (DbUpdateConcurrencyException ex)
{
CreateLogRow("Reconcile Voucher", "testUser", "Concurrency exception for " + voucher.StudentId, ex.Message);
if (!VoucherExists(voucher.VoucherId))
{
ModelState.AddModelError("InputStatus", "The Voucher for " + voucher.FullName + " cannot be found");
return View();
}
else
{
throw;
}
}
CreateLogRow("Reconcile Voucher", "testUser", "Voucher was edited for " + voucher.StudentId + " - " + voucher.FullName, null);
return View();
}
return View(voucher);
}
您通过调用
将所有属性标记为已修改 _context.Update(voucher);
要么省略此调用并让更改跟踪器确定更新的列,要么明确将 VoucherNumber 属性 标记为未修改。
db.Update(voucher);
db.Entry(voucher).Property(nameof(Voucher.VoucherNumber)).IsModified = false;
当您在调用中从 DbContext 获取实体并更新 属性 时,您不应调用 Update
,而应仅调用 SaveChanges
.
即
Voucher voucher = _context.Vouchers
.Single(m => m.VoucherId == id);
// ...
voucher.VoucherStatus = "Reconciled";
// ...
_context.SaveChanges();
Update
将生成一个语句,该语句将更新实体上的 all 列,虽然这应该排除标记为 DatabaseGeneratedOption.Identity
的列,但这可能这里不是这种情况。通过让更改跟踪在没有 Update 调用的情况下执行其操作,EF 将仅为更改的列生成 UPDATE 语句。
Update
在接受一个实体(如您注释掉的那样)和 attaching/updating 其整体状态时会更适用。我不推荐这种方法,因为它会覆盖所有值并且容易受到许多问题的影响,包括陈旧的数据更新和来自客户端的意外篡改。 (通过 man-in-the-browser/middle 攻击修改您的 UI 不允许的列)最好加载新的实体,验证传入数据,检查行 versions/modified 时间戳是否有陈旧更新等,而不是接受一个面值的实体并将其推入数据库。
编辑:如果这些 ID 在数据库中是 GUID,那么为什么不将它们转换为实体中的 GUID?