【问题标题】:Prevent updates to navigation properties in EF-core阻止更新 EF-core 中的导航属性
【发布时间】:2018-04-03 05:10:07
【问题描述】:

请问,当我们创建新的主实体时,如何防止 EF.core 尝试插入/更新外键表?

抛出此异常:

SqlException: Cannot insert explicit value for identity column in table 'clients' when IDENTITY_INSERT is set to OFF.
Cannot insert explicit value for identity column in table 'guards' when IDENTITY_INSERT is set to OFF.
Cannot insert explicit value for identity column in table 'penalties' when IDENTITY_INSERT is set to OFF.

我的代码如下:

  public class Offence
  {
    [Key]
    public Int32 offence_id { get; set; }

    public Int32? guard_id { get; set; }
    public Int32? penalty_id { get; set; }
    public DateTime? dt_recorded { get; set; }
    public Int32? salary_id { get; set; }
    public Decimal? amount { get; set; }
    public String status { get; set; }
    public Int32? site_id { get; set; }

    public Guard Guard { get; set; }
    public Salary Salary { get; set; }
    public Site Site { get; set; }
    public Penalty Penalty { get; set; }
  }

任何创建新 Offence 的尝试都会出错,因为 EF.core 会尝试为相关导航属性运行插入:

public Guard Guard { get; set; }
public Salary Salary { get; set; }
public Site Site { get; set; }
public Penalty Penalty { get; set; }

我们如何防止这种情况发生?

编辑:创建和更新代码

[HttpPost]
public async Task<IActionResult> Create([FromBody] Offence o)
{
  if (o == null)
  {
    return BadRequest();
  }

  o.last_modified_by = int.Parse(((ClaimsIdentity)User.Identity).Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value);
  o.last_modified = DateTime.Now;

  await db.AddAsync(o);
  await db.SaveChangesAsync();

  return CreatedAtRoute("GetOffenceAsync", new { id = o.offence_id }, o);
}

【问题讨论】:

  • 你能显示你的更新代码吗?
  • @H.Herzl 我添加了创建和更新代码,以及我遇到的错误
  • 我要看看db是什么类型,我猜是DbSet
  • dbDbContext ``` 私有只读 RSGContext 数据库;公共 OffencesController(RSGContext 上下文){ db = 上下文; } ```
  • 好的,您的导航属性似乎有值,请在保存之前检查您的导航属性是否有空值,顺便说一下,为什么您不使用 db.Set() 代替db.Add?

标签: entity-framework-core ef-core-2.0


【解决方案1】:

要让它工作,我必须在保存之前null-out 导航属性。

但是,如果使用CreatedAtRoute 发送回初始对象,则需要缓存nulled-out 属性并在返回之前将它们添加回:

实际代码:

[HttpPost]
public async Task<IActionResult> Create([FromBody] Offence o)
{
  if (o == null)
  {
    return BadRequest();
  }

  o.last_modified_by = int.Parse(((ClaimsIdentity)User.Identity).Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value);
  o.last_modified = DateTime.Now;

  var _g = o.Guard;
  var _p = o.Penalty;
  var _s = o.Site;

  o.Guard = null;
  o.Penalty = null;
  o.Site = null;

  await db.AddAsync(o);
  await db.SaveChangesAsync();

  o.Guard = _g;
  o.Penalty = _p;
  o.Site = _s;

  return CreatedAtRoute("GetOffenceAsync", new { id = o.offence_id }, o);
}

【讨论】:

    【解决方案2】:

    您的导航属性似乎有值,请在保存之前检查您的导航属性是否有空引用; EF Core 保存逻辑尝试保存导航属性(如果它们具有值)。

    如果有用请告诉我

    【讨论】:

      【解决方案3】:

      您需要将这些属性设置为virtual。这样 EF 就知道模型的组成部分以及导航属性是什么。这也将启用您需要的 LazyLoading 机制。

      public virtual Guard Guard { get; set; }
      public virtual Salary Salary { get; set; }
      public virtual Site Site { get; set; }
      public virtual Penalty Penalty { get; set; }
      

      【讨论】:

      • 感谢您的回复。无论是否虚拟,我仍然会遇到同样的错误
      • SqlException:当 IDENTITY_INSERT 设置为 OFF 时,无法在表“clients”中插入标识列的显式值。当 IDENTITY_INSERT 设置为 OFF 时,无法在表 'guards' 中插入标识列的显式值。当 IDENTITY_INSERT 设置为 OFF 时,无法为表“penalties”中的标识列插入显式值。
      • 每个表中都会出现异常,因此请发布每个表的类以及配置。如果这些类有一个名为Id 的属性,EF 将知道这是主键并相应地进行配置。但是,如果您为 pk 使用其他名称,则必须手动设置它。
      • 我所有的班级都有名为classname_id的pk,所以我每个班级都使用[key]
      猜你喜欢
      • 2021-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-16
      • 2018-10-22
      • 2018-10-10
      • 2020-02-23
      • 1970-01-01
      相关资源
      最近更新 更多