3

使用: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);
}
4

2 回答 2

3

This was fixed in EF5 and I've confirmed it still behaves correctly in EF6.

You can see notes of investigation on this issue - https://entityframework.codeplex.com/workitem/138.

于 2013-09-23T18:46:37.727 回答
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上述模型。没有创建数据库。

于 2012-04-05T00:17:00.463 回答