使用: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クラスでInversePropertyDataAnnotationを削除しても問題は解決するようですが、実際のMatchクラスには4人のPlayerが含まれているため、残念ながらこれを行うことはできません。したがって、明示的なマッピングが必要です。
そして最後に、オプション1を使用できることはわかっていますが、ナビゲーションプロパティの外部キーではなく、Idフィールドですべてのキー(プライマリおよび外部)を宣言する一貫性を好みます。そして技術的には、どちらの方法でも機能するはずです。
これは4.3.1の単なるバグですか?EFコードで最初に?
または、ForeignKeyとInversePropertyを2つの異なるプロパティから共通の3番目のプロパティにマッピングすることはサポートされていませんか?
どんな情報でも大歓迎です!
更新:2番目のバグ?
3番目のオプションも同様に機能するはずですが(Slaumaによって提案されているように)、データベースにエンティティを最初に追加しようとしたときにNullReferenceExceptionがスローされます。データベースが作成されることはありませんが、上記のオプション2にはこの問題はありません。これはEF4.1のSlaumaで機能したようですが、EF4.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);
}