Entity Framework Code Firstを使用して、1対1のオプションの関係を使用します。 2つのエンティティがあります。
public class PIIUser
{
public int Id { get; set; }
public int? LoyaltyUserDetailId { get; set; }
public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}
public class LoyaltyUserDetail
{
public int Id { get; set; }
public double? AvailablePoints { get; set; }
public int PIIUserId { get; set; }
public PIIUser PIIUser { get; set; }
}
PIIUser
にはLoyaltyUserDetail
を含めることができますが、LoyaltyUserDetail
にはPIIUser
が必要です。これらの流approachなアプローチ手法を試しました。
modelBuilder.Entity<PIIUser>()
.HasOptional(t => t.LoyaltyUserDetail)
.WithOptionalPrincipal(t => t.PIIUser)
.WillCascadeOnDelete(true);
このアプローチでは、LoyaltyUserDetailId
テーブルにPIIUsers
外部キーを作成しませんでした。
その後、次のコードを試しました。
modelBuilder.Entity<LoyaltyUserDetail>()
.HasRequired(t => t.PIIUser)
.WithRequiredDependent(t => t.LoyaltyUserDetail);
しかし今回は、EFはこれら2つのテーブルに外部キーを作成しませんでした。
この問題に関するアイデアはありますか?エンティティフレームワークFluent APIを使用して、1対1のオプションの関係を作成するにはどうすればよいですか?
EF Code Firstは、1:1
および1:0..1
の関係をサポートしています。後者が探しているものです(「1対0または1対1」)。
あなたの流atな試みは、ある場合には両端で必須であり、別の場合には両端でオプションと言っています。
必要なのは、一方の端にoptional、もう一方の端にrequiredです。
プログラミングE.F.コードファーストブックの例を次に示します
modelBuilder.Entity<PersonPhoto>()
.HasRequired(p => p.PhotoOf)
.WithOptional(p => p.Photo);
PersonPhoto
エンティティには、PhotoOf
型を指すPerson
というナビゲーションプロパティがあります。 Person
タイプには、Photo
タイプを指すPersonPhoto
というナビゲーションプロパティがあります。
2つの関連するクラスでは、各タイプの主キーを使用し、外部キー。つまり、LoyaltyUserDetailId
またはPIIUserId
プロパティは使用しません。代わりに、関係は両方のタイプのId
フィールドに依存します。
上記のような流れるようなAPIを使用している場合、LoyaltyUser.Id
を外部キーとして指定する必要はありません。EFはそれを把握します。
あなたのコードを自分でテストすることなく(私は自分の頭からこれをするのが嫌いです)...私はこれをあなたのコードに翻訳します
public class PIIUser
{
public int Id { get; set; }
public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}
public class LoyaltyUserDetail
{
public int Id { get; set; }
public double? AvailablePoints { get; set; }
public PIIUser PIIUser { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<LoyaltyUserDetail>()
.HasRequired(lu => lu.PIIUser )
.WithOptional(pi => pi.LoyaltyUserDetail );
}
つまり、LoyaltyUserDetails PIIUser
プロパティはrequiredであり、PIIUserのLoyaltyUserDetail
プロパティはオプションです。
あなたは反対側から始めることができます:
modelBuilder.Entity<PIIUser>()
.HasOptional(pi => pi.LoyaltyUserDetail)
.WithRequired(lu => lu.PIIUser);
現在、PIIUserのLoyaltyUserDetail
プロパティはオプションであり、LoyaltyUserのPIIUser
プロパティは必須であると言います。
常にパターンHAS/WITHを使用する必要があります。
HTHとFWIW、1対1(または1対0/1)の関係は、最初にコードで構成する最も複雑な関係の1つであるため、あなただけではありません! :)
LoyaltyUserDetail
とPIIUser
の間に1対多の関係がある場合と同じように、マッピングは
modelBuilder.Entity<LoyaltyUserDetail>()
.HasRequired(m => m.PIIUser )
.WithMany()
.HasForeignKey(c => c.LoyaltyUserDetailId);
EFは、必要なすべての外部キーを作成する必要があります WithManyは気にしないでください !
コードにはいくつかの問題があります。
1:1関係は、PK <-PK(一方のPK側もFKである)、またはPK <-FK + UCのいずれかです。 、FK側は非PKであり、UCがあります。あなたのコードは、FK <-FKを持っていることを示しています。両方の側がFKを持つように定義していますが、それは間違っています。 PIIUser
はPK側で、LoyaltyUserDetail
はFK側です。つまり、PIIUser
にはFKフィールドはありませんが、LoyaltyUserDetail
にはあります。
1:1関係がオプションである場合、FK側には少なくとも1つのNULL入力可能フィールドが必要です。
p.s.w.g.上記はあなたの質問に答えましたが、PIIUserでFKも定義したという間違いを犯しました。 したがって、LoyaltyUserDetail
でヌル可能FKフィールドを定義し、LoyaltyUserDetail
で属性を定義してFKフィールドをマークしますが、PIIUser
でFKフィールドを指定しないでください。 =
PK側(プリンシパルエンド)の側はないので、上記のp.s.w.g.のポストの下で説明した例外が発生します。
EFは一意の制約を処理できないため、1:1ではあまり得意ではありません。最初にコードの専門家ではないので、 UCを作成できるかどうかがわかりません。
(編集)btw:A 1:1 B(FK)は、Bのターゲットに作成されたFK制約が2つではなく、AのPKを指すことを意味します。
public class User
{
public int Id { get; set; }
public int? LoyaltyUserId { get; set; }
public virtual LoyaltyUser LoyaltyUser { get; set; }
}
public class LoyaltyUser
{
public int Id { get; set; }
public virtual User MainUser { get; set; }
}
modelBuilder.Entity<User>()
.HasOptional(x => x.LoyaltyUser)
.WithOptionalDependent(c => c.MainUser)
.WillCascadeOnDelete(false);
これはREFERENCEおよびFOREIGN KEYSの問題を解決します
更新または削除レコード
ForeignKey
属性をLoyaltyUserDetail
プロパティに追加してみてください:
public class PIIUser
{
...
public int? LoyaltyUserDetailId { get; set; }
[ForeignKey("LoyaltyUserDetailId")]
public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
...
}
そしてPIIUser
プロパティ:
public class LoyaltyUserDetail
{
...
public int PIIUserId { get; set; }
[ForeignKey("PIIUserId")]
public PIIUser PIIUser { get; set; }
...
}
上記のソリューションと混同される1つのことは、主キーが両方のテーブルで「Id」として定義されていることです。テーブル名に基づいた主キーがある場合、それは機能しません同じことを説明するクラス。つまり、オプションのテーブルはそれ自体の主キーを定義するのではなく、代わりにメインテーブルの同じキー名を使用する必要があります。
public class PIIUser
{
// For illustration purpose I have named the PK as PIIUserId instead of Id
// public int Id { get; set; }
public int PIIUserId { get; set; }
public int? LoyaltyUserDetailId { get; set; }
public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}
public class LoyaltyUserDetail
{
// Note: You cannot define a new Primary key separately as it would create one to many relationship
// public int LoyaltyUserDetailId { get; set; }
// Instead you would reuse the PIIUserId from the primary table, and you can mark this as Primary Key as well as foreign key to PIIUser table
public int PIIUserId { get; set; }
public double? AvailablePoints { get; set; }
public int PIIUserId { get; set; }
public PIIUser PIIUser { get; set; }
}
そして次に
modelBuilder.Entity<PIIUser>()
.HasOptional(pi => pi.LoyaltyUserDetail)
.WithRequired(lu => lu.PIIUser);
トリックを行うだろう、受け入れられた解決策はこれを明確に説明するのに失敗し、原因を見つけるために数時間私を捨てた