【问题标题】:Why does EF Code First [InverseProperty] attribute fail to work when used with [ForeignKey] attribute?为什么 EF Code First [InverseProperty] 属性与 [ForeignKey] 属性一起使用时无法正常工作?
【发布时间】:2012-04-18 17:22:54
【问题描述】:

使用:EF 4.3.1、Visual Studio 2010、SQL CE 4.0

我的理解是,在EF中用DataAnnotation声明外键时,可以采用以下两种方式之一:

选项 1-

[ForeignKey("Player1Home")]
public long? HPlayer1Id { get; set; }

public virtual Player Player1Home { get; set; }

选项 2-

public long? HPlayer1Id { get; set; }

[ForeignKey("HPlayer1Id")]
public virtual Player Player1Home { get; set; }

问题:

当 InverseProperty DataAnnotation 与 选项 2 一起使用时,除了 HPlayer1Id 之外,还会在数据库中生成一个额外的列 (Player1Home_Id)。
[Table("Matches")]
public class Match
{
    [Key]
    public long Id { get; set; }

    //-- Option 1 - THIS WORKS GREAT --//
    public long? HPlayer1Id { get; set; }
    [ForeignKey("HPlayer1Id")]
    public virtual Player Player1Home { get; set; }

    //-- Option 2 - THIS DOES NOT WORK, it generates an extra column in the database --//
    [ForeignKey("Player1Home")]
    public long? HPlayer1Id { get; set; }
    public virtual Player Player1Home { get; set; }
}

[Table("Players")]
public class Player
{
    [Key]
    public long Id { get; set; }

    [InverseProperty("Player1Home")]
    public virtual ICollection<Match> MatchesAsHome1 { get; set; }
}

当然,如果我将 HPlayer1Id 重命名为 Player1HomeId,那么选项 2 将再次正常工作。但 DataAnnotation 的全部目的是在“约定”无法自动确定匹配属性时允许显式命名。

删除 Player 类上的 InverseProperty DataAnnotation 似乎也解决了这个问题,但不幸的是我不能这样做,因为我的实际 Match 类中有四个 Player,因此我需要显式映射。

最后,我知道我可以只使用选项 1,但我更喜欢在 Id 字段上声明我的所有键(主键和外键)而不是在导航属性上声明外键的一致性。从技术上讲,任何一种方式都应该有效。

这只是 4.3.1 中的一个错误吗? EF 代码优先?

或者不支持将 ForeignKey 和 InverseProperty 从两个不同的属性映射到公共的第三个属性?

任何信息将不胜感激!

更新:第二个错误?

第三个选项应该也可以(如 Slauma 所建议的那样),但会在我第一次尝试将实体添加到数据库时引发 NullReferenceException。数据库永远不会被创建,而上面的选项 2 没有这个问题。看来这在 EF 4.1 上对 Slauma 有效,但对我在 EF 4.3.1 上无效。 (我在 SQL CE 4.0 中使用它)
[Table("Matches")]
public class Match
{
    [Key]
    public long Id { get; set; }
    [ForeignKey("Player1Home")]
    public long? HPlayer1Id { get; set; }
    [InverseProperty("MatchesAsHome1")]
    public virtual Player Player1Home { get; set; }
}

[Table("Players")]
public class Player
{
    [Key]
    public long Id { get; set; }
    public virtual ICollection<Match> MatchesAsHome1 { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Match> Matches { get; set; }
    public DbSet<Player> Players { get; set; }
}

用法:

try
{
    MyContext mc = new MyContext();
    //NullReferenceException gets thrown on the next call
    mc.Matches.Add(new Match());
    mc.SaveChanges();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

【问题讨论】:

  • 您是否已设置好使用注解 - 使用 fluent 方法配置应该没问题 - 注解有点棘手,混合各种东西可能会导致问题,我通常使用 fluent 解决。
  • @NSGaga,我肯定更喜欢 DataAnnotations,因为我个人认为这对我正在编写的软件的未来维护者来说更清楚。虽然我没有设置它,因为我使用 Fluent 处理一些注释不可用的东西。最重要的是上面的选项 1 和 3 应该可以工作,但它们没有。选项 2 目前当然提供了一种解决方法,但希望在正式的 .Net 4.5 发布之前,这将被修复以正常工作。
  • 好的,这是一个错误——我只是提供了一个替代解决方案——但如果问题是关于注释的,那么我不会打扰:)
  • @NSGaga,不用担心,是的,我正在严格研究 DataAnnotations 的问题。谢谢你看我的问题!
  • 我们已经确认这是 EF 4.3.1 和 EF5-beta2 中的一个错误。我们将进行修复并在可用时发布更新。现在请使用答案中建议的解决方法或使用 fluent API 进行配置。

标签: entity-framework foreign-keys ef-code-first data-annotations entity-framework-4.3


【解决方案1】:

这已在 EF5 中修复,我已确认它在 EF6 中仍能正常运行。

您可以查看对此问题的调查记录 - https://entityframework.codeplex.com/workitem/138

【讨论】:

  • 感谢修复确认!
【解决方案2】:

EF 4.1 中的行为相同。

您没有提到将InverseProperty 属性移动到关系另一端的选项:

[Table("Matches")]
public class Match
{
    [Key]
    public long Id { get; set; }

    [ForeignKey("Player1Home")]
    public long? HPlayer1Id { get; set; }

    [InverseProperty("MatchesAsHome1")]
    public virtual Player Player1Home { get; set; }
}

[Table("Players")]
public class Player
{
    [Key]
    public long Id { get; set; }

    public virtual ICollection<Match> MatchesAsHome1 { get; set; }
}

这对我有用,并没有创建额外的列。

您的选项 2 的行为在我看来像是代码优先的错误。

编辑

确认将版本从 EF 4.1 更改为 EF 4.3.1 会导致上述模型出现 NullReferenceException。未创建数据库。

【讨论】:

  • 使用您建议的方法(我同意应该可以),当我尝试调用 MyContext mc = new MyContext(); 时,我得到了 NullReferenceException mc.Matches.Add(新匹配());而我的问题中的选项 2 没有。我将使用我正在使用的代码更新我的问题。
  • 您得到了我的 +1,因为它应该可以工作,并且可以让我将 ForeignKey 保留在 Id 字段上。它肯定会产生与选项 1 不同的症状,因此它甚至可能是第二个错误。
  • @Scott:我已将版本从 EF 4.1 更改为 EF 4.3.1,但我也遇到了异常。错误报告的地方在这里:connect.microsoft.com/VisualStudio。但希望 EF 开发团队的人会在这里看到您的问题,因为他们最近宣布他们希望更加积极地支持 Stackoverflow。
  • Slauma,感谢您抽出宝贵时间研究此问题!我会报告错误。
猜你喜欢
  • 1970-01-01
  • 2016-09-06
  • 2011-08-15
  • 1970-01-01
  • 2017-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-02
相关资源
最近更新 更多