【问题标题】:ScriptIgnore attribute in Entity Framework 6 breaks foreign key attributeEntity Framework 6 中的 ScriptIgnore 属性破坏了外键属性
【发布时间】:2021-01-26 10:16:35
【问题描述】:

我们有一个使用 .NET Framework 4.5.2 和 Entity Framework 6.2.0 的现有代码优先数据库,其中模型在单独的类库中定义。

DAL 类库定义了自己的模型,继承自通用模型。

在 DAL 模型中,外键是使用 ForeignKey 属性定义的,因为有时无法应用默认命名约定。

我们为导航属性添加了ScriptIgnore 属性以防止出现序列化问题。

一切都按预期工作,除了在添加新迁移时会删除“一些”外键,使用默认命名约定添加新列,并将外键应用于这些新列。

只需删除 ScriptIgnore 属性,迁移就可以了,外键都保持原样。

并非所有外键都以这种方式被删除和重新创建,例如在同一张表上,有 3 个外键并且没有一个遵循命名约定,因此用 ForeignKeyScriptIgnore 属性装饰,但只有其中一个被迁移删除并重新创建。

我们无法弄清楚在哪种情况下ForeignKey 属性不受尊重以及导致这种行为的原因。

public class Alarm
{
   // ...
   public int? idChannel { get; set; }
   public int? idDevice { get; set; }
   public int? idScenario { get; set;  }
   // ...
}

public class EFAlarm : Alarm
{
   [ForeignKey("idChannel"), ScriptIgnore]
   public virtual EFChannel Channel { get; set; } // This one is kept as is

   [ForeignKey("idDevice"), ScriptIgnore]
   public virtual EFDevice Device{ get; set; } // This one is kept as is

   [ForeignKey("idScenario"), ScriptIgnore]
   public virtual EFScenario Scenario { get; set; } // This one is dropped and recreated
}

这里是迁移的摘录:

public override void Up()
{
   // ...
   DropForeignKey("dbo.fe_alarms", "idScenario", "dbo.scenario");
   DropIndex("dbo.fe_alarms", new[] { "idScenario" });
   AddColumn("dbo.fe_alarms", "Scenario_id", c => c.Int());
   CreateIndex("dbo.fe_alarms", "Scenario_id");
   AddForeignKey("dbo.fe_alarms", "Scenario_id", "dbo.scenario", "id");
   // ...
}

ScriptIgnore 属性在 System.Web 程序集中定义。 我们尝试使用在不同程序集中定义的其他自定义属性,但似乎没有一个会导致此类问题。 这种行为的原因可能是什么?

【问题讨论】:

  • 只是仔细检查:通过删除 ScriptIgnore 属性,迁移是否正确生成?
  • 是的,去掉 ScriptIgnore 属性外键是正确的。
  • 这些实体其实很大,但最终它们都有一个整数主键和一个属性列表。 FluentAPI 用于其他地方,但不是用于定义那些 ForeignKeys,只是 Channel 具有反向导航属性 HasMany(e => e.Alams).WithOptional(e => e.Channel)

标签: c# entity-framework


【解决方案1】:

经过一番研究,它似乎是 2018 年 4 月已经报告的 known issue。将 [ScriptIgnore] 添加到您的模型中有时会在您的迁移中产生问题。

不幸的是,从那以后它似乎没有被遵循,并且问题仍然存在。您可能可以关注该 Github 线程并评论您遇到了同样的问题。

与此同时,我有两个可能的建议:

  1. 从数据传输对象 (DTO) 中拆分域实体对象。然后,用[ScriptIgnore] 注释 DTO 中的属性并序列化 DTO 而不是实体(或者只是不包括 DTO 中的属性)。即使您没有遇到此错误,我也强烈建议您使用这种方法,因为我总是希望使我的域对象尽可能干净(没有 DB 或序列化属性)。实体到 DTO 的映射可以相当容易地手动完成,但我仍然建议使用流行的库 Automapper
  2. 保持一切原样,但无论何时创建新迁移,请记住手动编辑脚手架代码以删除 EF 尝试执行的错误删除/创建 FK 属性。

【讨论】:

  • 拆分域和 dto 模型通常迟早会得到回报。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-28
  • 1970-01-01
  • 2015-03-29
  • 1970-01-01
  • 2018-08-12
  • 2017-02-24
  • 1970-01-01
相关资源
最近更新 更多