Entity Framework 4 Code First (POCO) を使用して 1 対 1 の関係を宣言する方法は?
この質問 (Entity Framework 4 での一対一の関係)を見つけましたが、回答が参照している記事は役に立ちませんでした (1 対 1 の関係であるコード行が 1 行ありますが、それを定義する方法については言及されていません)。 )。
Entity Framework 4 Code First (POCO) を使用して 1 対 1 の関係を宣言する方法は?
この質問 (Entity Framework 4 での一対一の関係)を見つけましたが、回答が参照している記事は役に立ちませんでした (1 対 1 の関係であるコード行が 1 行ありますが、それを定義する方法については言及されていません)。 )。
3 つの方法:
A) ナビゲーション プロパティを持つ両方のクラスを相互に宣言します。テーブルの 1 つ (従属テーブル) を主キーの ForeignKey 属性でマークします。EF はこれから 1 対 1 で推論します。
public class AppUser
{
public int Id { get; set; }
public string Username { get; set; }
public OpenIdInfo OpenIdInfo { get; set; }
}
public class OpenIdInfo
{
[ForeignKey("AppUser")]
public int Id { get; set; }
public string OpenId { get; set; }
public AppUser AppUser { get; set; }
}
私は使っていませんしvirtual
、あなたも使うべきではありません。*
B) 明示的に記述された両方のテーブル名を使用して継承階層を宣言し、その結果、Table-Per-Type と共有主キーが生成されます。
using System.ComponentModel.DataAnnotations;
[Table("AppUser")]
public class AppUser
{
public int Id { get; set; }
public string Username { get; set; }
public OpenIdInfo OpenIdInfo { get; set; }
}
[Table("AdminUser")]
public class AdminUser : AppUser
{
public bool SuperAdmin { get; set; }
}
2 つのテーブルが得られます。1 つは AppUser 用、もう 1 つは AdminUser 用です。AdminUser は AppUser と 1 対 1 で依存関係があります。つまり、AdminUser を削除できますが、AdminUser がまだ AppUser を指しているときに AppUser を削除すると、制約違反エラーが発生します。</p>
C) EF で 1 対 1 を行うには、中途半端な方法が 2 つあります。
Entity-Splitting、単一のクラスがありますが、プライマリ テーブルと 1 つ以上の 1 対 1 の関連テーブルに格納されます。
オブジェクトのツリーが 1 つのテーブルにフラット化されるテーブル分割。たとえば、Address プロパティを持つクラスには、単一のテーブルにフラット化された Address_City などの Address オブジェクトの列があります。
*遅延ロードする場合は、任意の EF プロパティまたはコレクションに virtual を含めることができます。これにより、遅延ロードされたプロパティを持つオブジェクトを、たとえば MVC JSON コンバーターまたはオブジェクト階層をたどるその他のものに渡すと、無限ループまたは DB 全体のロードが発生する可能性があります。遅延読み込みは常に同期的に行われ、スレッドをブロックし、通知はありません。要約すると、コード、アプリ、またはサーバーを凍結する方法のリストは長いです。EF クラスで virtual を使用しないでください。はい、それを使用するコードサンプルがインターネット上にたくさんあります。いいえ、まだ使用しないでください。
このようなものを探しているだけですか?
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public Profile Profile { get; set; }
public int ProfileId { get; set; }
}
public class Profile
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PostalCode { get; set; }
// etc...
}
public class UserMapping : EntityConfiguration<User>
{
public UserMapping()
{
this.HasKey(u => u.Id);
this.Property(u => u.Username).HasMaxLength(32);
// User has ONE profile.
this.HasRequired(u => u.Profile);
}
}
public class ProfileMapping : EntityConfiguration<Profile>
{
public ProfileMapping()
{
this.HasKey(p => p.Id);
this.Property(p => p.FirstName).HasMaxLength(32);
this.Property(p => p.LastName).HasMaxLength(32);
this.Property(p => p.PostalCode).HasMaxLength(6);
}
}
編集:ええ、私の前にVSはありませんでしたがUserMapping
、現在の代わりに次の行を追加し、(HasRequired
追加したProfileId
代わりに)プロパティを追加する必要がありProfile_Id
ます:
this.HasRequired(u => u.Profile).HasConstraint((u, p) => u.ProfileId == p.Id);
現在、これを回避する方法はないと思いますが、CTP4 しかないため、変更されると確信しています。次のように言えばよかったです。
this.HasRequired(u => u.Profile).WithSingle().Map(
new StoreForeignKeyName("ProfileId"));
ProfileId
この方法では、プロパティを含める必要はありません。たぶん、現在これを回避する方法があり、私が考えるにはまだ早朝です:)。
.Include("Profile")
また、「ナビゲーション プロパティ」を含めたい場合は、忘れずに呼び出してください。
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public virtual Profile Profile { get; set; }
}
public class Profile
{
public int Id { get; set; }
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PostalCode { get; set; }
}
仮想プロファイルとユーザー ID を追加すると、そこに到達するはずです。