12

Entity Framework 4 Code First (POCO) を使用して 1 対 1 の関係を宣言する方法は?

この質問 (Entity Framework 4 での一対一の関係)を見つけましたが、回答が参照している記事は役に立ちませんでした (1 対 1 の関係であるコード行が 1 行ありますが、それを定義する方法については言及されていません)。 )。

4

4 に答える 4

22

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; }
}

http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations. aspx

私は使っていませんし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 を使用しないでください。はい、それを使用するコードサンプルがインターネット上にたくさんあります。いいえ、まだ使用しないでください。

于 2012-05-31T16:57:25.843 に答える
11

このようなものを探しているだけですか?

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")また、「ナビゲーション プロパティ」を含めたい場合は、忘れずに呼び出してください。

于 2010-09-01T22:43:55.557 に答える
1
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 を追加すると、そこに到達するはずです。

于 2010-09-15T02:51:42.897 に答える