Entity Framework 6.1.3には次のデータモデルがあります。
using System.Data.Entity;
public class Student
{
public int Id { get; set; }
public virtual Contact Contact { get; set; }
}
public class Contact
{
public int Id { get; set; }
public virtual Student Student { get; set; }
}
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder builder)
{
builder.Entity<Contact>()
.HasOptional(x => x.Student)
.WithOptionalDependent(x => x.Contact)
.WillCascadeOnDelete(true);
}
}
public static class Program
{
private static void Main()
{
Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
using (var context = new MyContext())
context.Database.Initialize(force: true);
}
}
このコードを起動すると、目的とする正確なテーブル構造が得られます。
dbo.Contacts
Id (PK)
Student_Id (FK, NULL, CASCADE ON DELETE)
dbo.Students
Id (PK)
ただし、ここでContact
エンティティで使用できるようにStudent_Id
プロパティを追加します。そのため、Student_Id
ナビゲーションを介して他のテーブルを結合する必要なく、.Student.Id
を読み取ることができます。
プロパティをContact
エンティティに追加すると、2つの列Student_Id
とStudent_Id1
が表示されるか、Each property name in a type must be unique.
というエラーメッセージが表示されます。
列はすでにデータベースにありますが、必要なのはエンティティに含めることだけですが、なぜそんなに面倒なのですか?解決策はありますか?
GitHubで質問 の後に、Entity Framework Program Managerから応答を得ることができました。
残念ながら、これはEF6の制限です。主キープロパティでもない限り、1対1の関係で外部キープロパティを持つことはできません。これは、EF6が代替キー/一意のインデックスをサポートしていないため、非主キープロパティが一意であることを強制できないためです。外部キーのプロパティがエンティティにないときにそれを実行できるという事実は、ちょっとした癖です...しかし、明らかに私たちが削除するものではありません????。
BTW代替キー(およびこのシナリオ)は、EF Coreでサポートされています。
– Rowan Miller @ https://github.com/aspnet/EntityFramework6/issues/159#issuecomment-274889438
依存エンティティのFKプロパティを1対1の関係で宣言する場合は、PKとしても使用する必要があると思います。 EFコードが最初 必須 依存エンティティのPKも関係のFKでなければならない:
public class Contact
{
[Key,ForeignKey("Student")]
public int StudentId { get; set; }
public virtual Student Student { get; set; }
}
しかし、これはあなたが探しているものではないと思います。したがって、ここには3つのオプションがあると思います。
私の経験では、最後のものはあなたが達成しようとしていることに最も適応しています(しかしそれは私の意見です)。この場合、必要に応じてFkプロパティを操作できます。コレクションによってContact
のStudent
ナビゲーションプロパティを変更する必要があります(またはこのナビゲーションプロパティを省略して、単方向の関係):
public class Student
{
public int Id { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
}
構成は次のようになります。
builder.Entity<Contact>()
.HasOptional(x => x.Student)
.WithMany(x => x.Contacts)
.HasForeignKey(x => x.StudentId)
.WillCascadeOnDelete(true);
4番目のオプションは、2つの単方向の関係を作成することです。
builder.Entity<Contact>()
.HasOptional(x => x.Student)
.WithMany()
.HasForeignKey(x => x.StudentId)
.WillCascadeOnDelete(true);
builder.Entity<Student>()
.HasOptional(x => x.Contact)
.WithMany()
.HasForeignKey(x => x.ContactId)
.WillCascadeOnDelete(true);
しかし、このオプションは2つのテーブル間の実際の関係を壊します。