背景については、次の投稿を参照してください。
ナビゲーションプロパティのないエンティティフレームワーク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; }
}
しかし、これは失敗しました。この結果、ForeignKey
はMemberDataSet
クラスの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
}
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();
あなたの元のアイデアは正しかったと思いますが、わずかな例外があります。外部キーを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
私はあなたが正しかったと思います(私があなたを正しく理解していれば)。 [ForeignKeyAttribute]
は、対応する外部キーで使用されます。リンクされたオブジェクトの主キーではありません。
This is my object, and the foreign key is DeferredDataId
オブジェクト内のId
は外部キー(主キー)でもリンクされたオブジェクトのID
も外部キー(リレーションの反対側の主キー)ではありません
私があなたを正しく理解したことを願っています:)わからないので。