web-dev-qa-db-ja.com

エンティティフレームワークコードのForeignKey属性を最初に理解する

背景については、次の投稿を参照してください。

ナビゲーションプロパティのないエンティティフレームワーク1対0または1つの関係

ナビゲーションプロパティを決定するForeignKeyを保持するクラスのプロパティを示すために、ForeignKeyが使用されると常に考えていました。

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("DeferredDataId")]
    public virtual DeferredData DeferredData { get; set; }
}

しかし、リンクされた投稿で、これは正しくないこと、およびDeferredDataの主キーがIdと呼ばれているため、実際に必要であることがわかりました。

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("Id")]
    public virtual DeferredData DeferredData { get; set; }
}

つまり、ForeignKeyは他のクラスを指すために使用されます。

次に、他の参照の一部を変更しました。

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("Id")]
    public virtual DeferredData DeferredData { get; set; }

    public int? SignedOffById { get; set; }
    [ForeignKey("UserId")]
    public virtual UserProfile SignedOffBy { get; set; }
}

しかし、これは失敗しました。この結果、ForeignKeyMemberDataSetクラスのIDを指す必要がありました。

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public int? DeferredDataId { get; set; }
    [ForeignKey("Id")]
    public virtual DeferredData DeferredData { get; set; }

    public int? SignedOffById { get; set; }
    [ForeignKey("SignedOffById")]
    public virtual UserProfile SignedOffBy { get; set; }
}

これは、この2番目の関係は1対多であるのに対し、最初の関係は1対0または1であり、事実上関係の主な終わりが異なるためだと思いますが、この記事/良い記事への参照をある程度理解していただければ幸いです何が起こっているのか、ForeignKeyが何をしているかを正確に理解する。

また、上記の例で_public int? DeferredDataId { get; set; }は、DeferredDataに明示的にリンクされていない場合、方程式に適合します。これが慣例により一致することを嬉しく思いますが、これを明示的にどのように伝えるでしょうか?別の名前だったら?この話で見たForeignKey属性の使用についての例ですが、これは上記のすべての場合に答えになるわけではありません!

私のモデルには多くの参照があるので、特定の問題を修正するのではなく、問題を理解しようとしていますので、それぞれにどのアプローチを取るかを確立する必要があります。

ありがとう。

編集

役立つ他のクラスを追加しました:

public class DeferredData
{

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    //other properties
}

public class UserProfile
{

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }

    //other properties
}
26
Mark007

1..0関係の必要な側MemberDataSetには、DeferredDataへのFKがあってはなりません。代わりに、DeferredDataのPKはMemberDataSetへのFKである必要があります(共有主キーとして知られています)

public class MemberDataSet
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public virtual DeferredData DeferredData { get; set; }
}

public class DeferredData
{
    // DeferredData.Id is both the PK and a FK to MemberDataSet
    [Key]
    [DatabaseGenerated( DatabaseGeneratedOption.None )]
    [ForeignKey( "MemberDataSet" )]
    public int Id { get; set; }

    [Required]
    public virtual MemberDataSet MemberDataSet { get; set; }
}

Fluent API:

modelBuilder.Entity<MemberDataSet>()
    .HasOptional( mds => mds.DeferredData )
    .WithRequired()
    .WillCascadeOnDelete();
26
Moho

あなたの元のアイデアは正しかったと思いますが、わずかな例外があります。外部キーをMemberDataSetに置くことにより、ゼロまたは1対多の関係が必要であることを意味します。

あなたの例では、MemberDataSet.DeferredDataはオプションであり、DeferredDataは多くのMemberDataSetインスタンスから参照できます。

流fluentな構文では、これは次のように表現されます。

modelBuilder.Entity<MemberDataSet>()
    .HasOptional(dataSet => dataSet.DeferredData)
    .WithMany()
    .HasForeignKey(deferredData => deferredData.DeferredDataId);

これを1対0または1のプロパティにするために、MemberDataSetのDeferredDataId列に一意の(nullではない)キー制約を設定できます。これは、DeferredDataエンティティが単一のMemberDataSetエンティティによってのみ参照されることを意味します。

CREATE UNIQUE INDEX unique_MemberDataSet_DeferredDataId ON MemberDataSet(DeferredDataId) WHERE DeferredDataId IS NOT NULL

注: この種類のフィルター処理されたキーは、SQL Server 2008以降でのみ使用可能です

0
David Kirkland

私はあなたが正しかったと思います(私があなたを正しく理解していれば)。 [ForeignKeyAttribute]は、対応する外部キーで使用されます。リンクされたオブジェクトの主キーではありません。

This is my object, and the foreign key is DeferredDataId

オブジェクト内のIdは外部キー(主キー)でもリンクされたオブジェクトのIDも外部キー(リレーションの反対側の主キー)ではありません

私があなたを正しく理解したことを願っています:)わからないので。

0
csteinmueller