Apa yang dimaksud akhir prinsipal dari asosiasi dalam hubungan 1: 1 dalam kerangka Entity

269
public class Foo
{
    public string FooId{get;set;}
    public Boo Boo{get;set;}
}


public class Boo
{
    public string BooId{get;set;}
    public Foo Foo{get;set;}
}

Saya mencoba melakukan ini di Entity Framework ketika saya mendapatkan kesalahan:

Tidak dapat menentukan akhir utama dari hubungan antara tipe 'ConsoleApplication5.Boo' dan 'ConsoleApplication5.Foo'. Akhir utama dari asosiasi ini harus dikonfigurasikan secara eksplisit menggunakan API yang lancar hubungan atau anotasi data.

Saya telah melihat pertanyaan tentang StackOverflow dengan solusi untuk kesalahan ini, tetapi saya ingin memahami apa arti istilah "akhir pokok".

taher chhabrawala
sumber
Lihat docs.microsoft.com/en-us/ef/core/modeling/relationships untuk penjelasan istilah
DeepSpace101

Jawaban:

378

Dalam hubungan satu-ke-satu, satu ujung haruslah pokok dan ujung kedua harus tergantung. Ujung kepala adalah ujung yang akan dimasukkan lebih dulu dan yang bisa ada tanpa ujung yang tergantung. Dependent end adalah yang harus dimasukkan setelah kepala sekolah karena memiliki kunci asing ke kepala sekolah.

Dalam hal kerangka entitas, FK dalam tanggungan juga harus merupakan PK-nya sehingga dalam kasus Anda, Anda harus menggunakan:

public class Boo
{
    [Key, ForeignKey("Foo")]
    public string BooId{get;set;}
    public Foo Foo{get;set;}
}

Atau pemetaan yang lancar

modelBuilder.Entity<Foo>()
            .HasOptional(f => f.Boo)
            .WithRequired(s => s.Foo);
Ladislav Mrnka
sumber
6
@ Ladislav, saya perlu membuat dua tabel independen yang keduanya memiliki referensi opsional satu sama lain (satu ke satu), saya ingin mereka berdua memiliki PK masing-masing, bagaimana ini mungkin? Saya memposting pertanyaan terpisah .
Shimmy Weitzhandler
10
Anda tidak tahu berapa jam yang dibutuhkan untuk menemukan jawaban untuk ini - dokumentasi ms adalah POOOOOOP ty.
gangelo
1
Catatan Anda mungkin perlu menambahkan menggunakan System.ComponentModel.DataAnnotations.Schema; untuk mendapatkan ForeignKey di VS2012
stuartdotnet
2
Apakah itu berarti itu Fooadalah kepala sekolah?
bflemi3
8
@ bflemi3 Anda benar Bootergantung, memerlukan Foo, dan mendapatkan kunci asing. Fooadalah kepala sekolah dan dapat ada tanpa a Boo.
Colin
182

Anda juga dapat menggunakan [Required]atribut anotasi data untuk menyelesaikan ini:

public class Foo
{
    public string FooId { get; set; }

    public Boo Boo { get; set; }
}

public class Boo
{
    public string BooId { get; set; }

    [Required]
    public Foo Foo {get; set; }
}

Foodiperlukan untuk Boo.

Leniel Maccaferri
sumber
Ini benar untuk kode saya berikut ini di mana saya ingin peta antara keduanya sebagai entitas kelas publik entitas terpisah {public int Id {get; set; }} pengguna kelas publik {public int Id {get; set; }} UserGroup public class {[Key] public int Id {get; set; } [Wajib] Organisasi Organisasi virtual publik {get; set; } [Wajib] Pengguna Pengguna publik virtual {get; set; }}
AndyM
Saya menggunakan Oracle dan tidak ada api yang lancar bekerja untuk saya. Terima kasih kawan Sangat sederhana.
CameronP
11
Ketahuilah bahwa saat menggunakan solusi ini, Anda akan mendapatkan pengecualian validasi saat Anda mencoba dan memperbarui Booyang baru saja diambil dari database, kecuali jika Anda pertama kali memicu lazy-load Fooproperti. entitasframework.codeplex.com/SourceControl/network/forks/…
NathanAldenSr
2
bukankah seharusnya Boo Boovirtual?
Simon_Weaver
1
@NathanAldenSr tautannya buruk sekarang, bagaimana Anda melakukan perubahan itu?
CamHart
9

Ini mengacu pada jawaban @Ladislav Mrnka tentang penggunaan api yang lancar untuk mengkonfigurasi hubungan satu-ke-satu.

Punya situasi di mana memiliki FK of dependent must be it's PKtidak layak.

Misalnya, Foosudah memiliki hubungan satu-ke-banyak dengan Bar.

public class Foo {
   public Guid FooId;
   public virtual ICollection<> Bars; 
}
public class Bar {
   //PK
   public Guid BarId;
   //FK to Foo
   public Guid FooId;
   public virtual Foo Foo;
}

Sekarang, kami harus menambahkan hubungan satu-ke-satu lainnya antara Foo dan Bar.

public class Foo {
   public Guid FooId;
   public Guid PrimaryBarId;// needs to be removed(from entity),as we specify it in fluent api
   public virtual Bar PrimaryBar;
   public virtual ICollection<> Bars;
}
public class Bar {
   public Guid BarId;
   public Guid FooId;
   public virtual Foo PrimaryBarOfFoo;
   public virtual Foo Foo;
}

Berikut ini cara menentukan hubungan satu-ke-satu menggunakan api fasih:

modelBuilder.Entity<Bar>()
            .HasOptional(p => p.PrimaryBarOfFoo)
            .WithOptionalPrincipal(o => o.PrimaryBar)
            .Map(x => x.MapKey("PrimaryBarId"));

Perhatikan bahwa saat menambahkan PrimaryBarIdperlu dihapus, karena kami menetapkannya melalui api yang lancar.

Perhatikan juga bahwa nama metode [WithOptionalPrincipal()][1]agak ironis. Dalam hal ini, Kepala Sekolah adalah Bar. Deskripsi WithOptionalDependent () pada msdn membuatnya lebih jelas.

Sudarshan_SMD
sumber
2
Bagaimana jika Anda benar-benar ingin yang PrimaryBarIdproperti? Ini konyol bagi saya. Jika saya menambahkan properti dan mengatakan itu adalah kunci asing, saya mendapatkan kesalahan. Tetapi jika saya tidak memiliki properti, maka EF akan membuatnya. Apa bedanya?
Chris Pratt
1
@ ChrisPratt Ini mungkin kedengarannya tidak masuk akal. Saya tiba di solusi ini setelah jejak dan kesalahan. Tidak dapat mengonfigurasi pemetaan satu-ke-satu ketika saya memiliki PrimayBarIdproperti di Fooentitas. Kemungkinan solusi yang sama yang Anda coba. Keterbatasan dalam EF mungkin?
Sudarshan_SMD
3
Ya itu dia. Saya datang untuk mengetahui bahwa EF hingga hari ini tidak pernah menerapkan indeks unik. Akibatnya, satu-satunya cara yang tersedia untuk memetakan satu-ke-satu adalah dengan menggunakan kunci utama dari ujung utama sebagai kunci utama dari ujung tergantung, karena kunci primer pada dasarnya unik. Dengan kata lain, mereka setengah mengimplementasikannya dan mengambil jalan pintas yang menentukan bahwa tabel Anda harus dirancang dengan cara yang tidak standar.
Chris Pratt