จุดสิ้นสุดหลักของสมาคมหมายถึงอะไรในความสัมพันธ์ 1: 1 ในกรอบ 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;}
}

ฉันพยายามทำสิ่งนี้ใน Entity Framework เมื่อฉันพบข้อผิดพลาด:

ไม่สามารถระบุจุดสิ้นสุดหลักของการเชื่อมโยงระหว่างประเภท 'ConsoleApplication5.Boo' และ 'ConsoleApplication5.Foo' จุดสิ้นสุดหลักของการเชื่อมโยงนี้ต้องกำหนดค่าอย่างชัดเจนโดยใช้ API ความคล่องแคล่วของความสัมพันธ์หรือหมายเหตุประกอบข้อมูล

ฉันได้เห็นคำถามเกี่ยวกับ StackOverflow ด้วยวิธีแก้ปัญหาสำหรับข้อผิดพลาดนี้ แต่ฉันต้องการเข้าใจความหมายของคำว่า "การสิ้นสุดที่สำคัญ"


ดูdocs.microsoft.com/en-us/ef/core/modeling/relationshipsเพื่อดูคำอธิบายของข้อกำหนด
DeepSpace101

คำตอบ:


378

ในความสัมพันธ์แบบหนึ่งต่อหนึ่งด้านหนึ่งต้องเป็นตัวการและส่วนท้ายที่สองต้องขึ้นอยู่กับ จุดสิ้นสุดหลักคือส่วนที่จะถูกแทรกก่อนและสามารถอยู่ได้โดยไม่มีส่วนเชื่อมต่อ สิ้นสุดขึ้นอยู่กับเป็นสิ่งที่จะต้องถูกแทรกหลังจากเงินต้นเพราะมันมีคีย์ต่างประเทศเพื่อเงินต้น

ในกรณีที่เฟรมเวิร์กเอนทิตี FK ขึ้นอยู่กับจะต้องเป็นของ PK ด้วยในกรณีของคุณคุณควรใช้:

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

หรือการทำแผนที่คล่องแคล่ว

modelBuilder.Entity<Foo>()
            .HasOptional(f => f.Boo)
            .WithRequired(s => s.Foo);

6
@ Ladislav ฉันต้องสร้างตารางอิสระสองตารางที่ทั้งสองมีการอ้างอิงซึ่งกันและกัน (หนึ่งต่อหนึ่ง) ฉันต้องการให้ทั้งคู่มี PKs ของตัวเองเป็นไปได้อย่างไร ผมโพสต์คำถามที่แยกต่างหาก
Shimmy Weitzhandler

10
คุณไม่ทราบว่าต้องใช้เวลากี่ชั่วโมงในการหาคำตอบ - เอกสาร ms คือ POOOOOOP
gangelo

1
หมายเหตุคุณอาจต้องเพิ่มการใช้ System.ComponentModel.DataAnnotations.Schema; เพื่อรับ ForeignKey ใน VS2012
stuartdotnet

2
นั่นหมายความว่าFooเป็นหลักการหรือไม่
bflemi3

8
@ bflemi3 คุณถูกต้องBooขึ้นอยู่กับว่าต้องมีFooและรับ foreign key เป็นหลักและสามารถอยู่ได้โดยไม่ต้องFoo Boo
โคลิน

182

คุณยังสามารถใช้[Required]แอ็ตทริบิวต์หมายเหตุประกอบข้อมูลเพื่อแก้ไขปัญหานี้:

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; }
}

FooBooเป็นสิ่งจำเป็นสำหรับ


นี่ถูกต้องสำหรับรหัสต่อไปนี้ของฉันที่ฉันต้องการแผนที่ระหว่างสองเป็นองค์กรสาธารณะชั้นแยกองค์กร {สาธารณะ int Id {รับ; ตั้ง; }} ผู้ใช้ระดับสาธารณะ {รหัสสาธารณะสาธารณะ {รับ; ตั้ง; }} กลุ่มผู้ใช้สาธารณะระดับ {{คีย์] รหัสสาธารณะสาธารณะ {รับ; ตั้ง; } [จำเป็น] สาธารณะองค์กรเสมือนองค์กร {รับ; ตั้ง; } [จำเป็น] ผู้ใช้เสมือนผู้ใช้สาธารณะ {รับ; ตั้ง; }}
AndyM

ฉันใช้ Oracle และไม่มี API ที่คล่องแคล่วสำหรับฉัน ขอบคุณครับ ง่ายมาก
CameronP

11
โปรดทราบว่าเมื่อใช้โซลูชันนี้คุณจะได้รับข้อยกเว้นในการตรวจสอบความถูกต้องเมื่อคุณลองและอัปเดตสิ่งBooที่คุณเพิ่งเรียกคืนจากฐานข้อมูลเว้นแต่คุณจะทริกเกอร์การโหลดFooคุณสมบัติ entityframework.codeplex.com/SourceControl/network/forks/…
NathanAldenSr

2
ไม่ควรBoo Booเป็นเสมือนจริงหรือ
Simon_Weaver

1
@NathanAldenSr ลิงก์ไม่ดีตอนนี้คุณจะทำการเปลี่ยนแปลงอย่างไร
CamHart

9

นี่คือการอ้างอิงถึงคำตอบของ @Ladislav Mrnka เกี่ยวกับการใช้ API ได้อย่างคล่องแคล่วสำหรับการกำหนดค่าความสัมพันธ์แบบหนึ่งต่อหนึ่ง

มีสถานการณ์ที่FK of dependent must be it's PKไม่สามารถทำได้

เช่นFooมีความสัมพันธ์แบบหนึ่งต่อหลายคน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;
}

ตอนนี้เราต้องเพิ่มความสัมพันธ์แบบหนึ่งต่อหนึ่งระหว่างฟูกับบาร์

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;
}

นี่คือวิธีระบุความสัมพันธ์แบบหนึ่งต่อหนึ่งโดยใช้ API ได้อย่างคล่องแคล่ว:

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

โปรดทราบว่าในขณะที่การเพิ่มPrimaryBarIdจะต้องลบออกตามที่เราระบุผ่าน API ได้อย่างคล่องแคล่ว

โปรดทราบด้วยว่าชื่อวิธีการ[WithOptionalPrincipal()][1]นั้นเป็นเรื่องที่น่าขัน ในกรณีนี้อาจารย์ใหญ่คือบาร์ WithOptionalD พึ่งพาคำอธิบาย()บนmsdnทำให้ชัดเจนยิ่งขึ้น


2
เกิดอะไรขึ้นถ้าคุณจริงต้องการPrimaryBarIdทรัพย์สิน? นี่มันไร้สาระสำหรับฉัน ถ้าฉันเพิ่มคุณสมบัติและบอกว่าเป็นรหัสต่างประเทศฉันได้รับข้อผิดพลาด แต่ถ้าฉันไม่มีทรัพย์สิน EF ก็จะสร้างมันต่อไป ความแตกต่างคืออะไร?
Chris Pratt

1
@ChrisPratt สิ่งนี้อาจฟังดูไม่สมเหตุสมผล ฉันมาถึงวิธีแก้ไขปัญหานี้หลังจากทางและข้อผิดพลาด ไม่สามารถกำหนดค่าการแมปแบบหนึ่งต่อหนึ่งเมื่อฉันมีPrimayBarIdคุณสมบัติในFooเอนทิตี น่าจะเป็นทางออกเดียวกันกับที่คุณลอง อาจมีข้อ จำกัด ใน EF?
Sudarshan_SMD

3
ใช่มันเป็น ฉันพบว่า EF มาจนถึงทุกวันนี้ไม่เคยใช้ดัชนีที่ไม่ซ้ำใคร ดังนั้นวิธีเดียวที่มีในการแม็พแบบหนึ่งต่อหนึ่งคือการใช้คีย์หลักของการสิ้นสุดหลักเป็นคีย์หลักของการสิ้นสุดเนื่องจากขึ้นอยู่กับคีย์หลักโดยธรรมชาติที่ไม่ซ้ำกัน กล่าวอีกนัยหนึ่งพวกเขานำมาใช้ครึ่งหนึ่งและใช้ทางลัดที่บอกว่าตารางของคุณต้องได้รับการออกแบบในแบบที่ไม่ได้มาตรฐาน
Chris Pratt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.