Entity framework 为什么EF Code First[InverseProperty]属性与[ForeignKey]属性一起使用时无法工作?

Entity framework 为什么EF Code First[InverseProperty]属性与[ForeignKey]属性一起使用时无法工作?,entity-framework,foreign-keys,ef-code-first,data-annotations,entity-framework-4.3,Entity Framework,Foreign Keys,Ef Code First,Data Annotations,Entity Framework 4.3,使用:EF 4.3.1、Visual Studio 2010、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

使用:EF 4.3.1、Visual Studio 2010、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; }
}
我的理解是,在EF中使用DataAnnotation声明外键时,可以通过以下方式之一执行:

选择1-

选择2-

问题:当InverseProperty DataAnnotation与选项2一起使用时,除了HPlayer1Id之外,还会在数据库(Player1Home\u 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; }
}

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; }
}
[表(“匹配项”)]
公开课比赛
{
[关键]
公共长Id{get;set;}
[外键(“Player1Home”)]
public long?HPlayer1Id{get;set;}
[InverseProperty(“MatchesAsHome1”)]
公共虚拟玩家Player1Home{get;set;}
}
[表(“玩家”)]
公开课选手
{
[关键]
公共长Id{get;set;}
公共虚拟ICollection MatchesAsHome1{get;set;}
}
这对我很有效,没有创建额外的列

在我看来,选项2的行为就像是代码优先的bug

编辑


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

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


您可以看到关于这个问题的调查说明-。

使用您建议的方法(我同意应该可以),当我尝试调用MyContext mc=new MyContext()时,我得到一个NullReferenceException;mc.Matches.Add(new Match());而我的问题中的选项2没有。我将用我正在使用的代码更新我的问题。不过你得到了+1,因为它应该可以工作,并且允许我将外键保留在Id字段上。它肯定会产生与选项1不同的症状,因此它甚至可能是第二个错误。@Scott:我已将版本从EF 4.1更改为EF 4.3.1,并且我也得到了异常。错误报告的位置在此处:。但希望EF开发团队的人能在这里看到您的问题,因为他们最近宣布希望在Stackoverflow上获得更积极的支持。Slauma,感谢您花时间研究这个问题!我将报告错误。您是否已开始使用注释-使用fluent方法配置应该可以-注释有点棘手,混合各种内容可能会导致问题,我通常使用fluent解决。@NSGaga,我当然更喜欢DataAnnotation,因为我个人认为它对于我正在编写的软件的未来维护者来说更为清晰。虽然我没有设置它,因为我使用Fluent处理一些注释不可用的事情。重要的是,上面的选项1和3应该有效,但它们不起作用。选项2当然提供了一个暂时的解决方案,但希望在官方的.Net 4.5发布之前,这将被修复,使其能够正常工作。好吧,这是一个bug-我只是提供了一个替代解决方案-但是如果问题严格地说是关于注释,那么我就不麻烦了:)@NSGaga,不用担心,是的,我一直在研究数据注释的问题。谢谢你看了我的问题!我们已经确认这是EF 4.3.1和EF5-beta2中的一个错误。我们将进行修复,并在更新可用时发布更新。现在,请使用答案中建议的解决方法或使用fluent API进行配置。感谢您的修复确认!
[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);
}
[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; }
}