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