Kết thúc chính của một hiệp hội có ý nghĩa gì trong mối quan hệ 1: 1 trong khung Thực thể


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

Tôi đã cố gắng thực hiện điều này trong Entity Framework khi tôi gặp lỗi:

Không thể xác định kết thúc chính của liên kết giữa các loại 'ConsoleApplication5.Boo' và 'ConsoleApplication5.Foo'. Kết thúc chính của liên kết này phải được cấu hình rõ ràng bằng cách sử dụng API lưu loát mối quan hệ hoặc chú thích dữ liệu.

Tôi đã thấy các câu hỏi trên StackOverflow với một giải pháp cho lỗi này, nhưng tôi muốn hiểu thuật ngữ "kết thúc chính" nghĩa là gì.


Xem docs.microsoft.com/en-us/ef/core/modeling/relationships để được giải thích về các điều khoản
DeepSpace101

Câu trả lời:


378

Trong mối quan hệ một đối một, một đầu phải là gốc và đầu thứ hai phải phụ thuộc. Kết thúc gốc là cái sẽ được chèn trước và có thể tồn tại mà không cần phụ thuộc. Đầu phụ thuộc là đầu cuối phải được chèn sau hiệu trưởng vì nó có khóa ngoại đối với hiệu trưởng.

Trong trường hợp khung thực thể FK phụ thuộc cũng phải là PK của nó, vì vậy trong trường hợp của bạn, bạn nên sử dụng:

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

Hoặc lập bản đồ lưu loát

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

6
@Ladislav, tôi cần tạo hai bảng độc lập mà cả hai đều có tham chiếu tùy chọn cho nhau (một đối một), tôi muốn cả hai đều có PK riêng, làm sao có thể? Tôi đã đăng một câu hỏi riêng biệt .
Shimmy Weitzhandler

10
Bạn không biết phải mất bao nhiêu giờ để tìm câu trả lời cho điều này - tài liệu ms là POOOOOOP ty.
gangelo

1
Lưu ý bạn có thể cần thêm bằng System.ComponentModel.DataAnnotations.Schema; để get ForeignKey trong VS2012
stuartdotnet

2
Điều đó có nghĩa là đó Foolà hiệu trưởng?
bflemi3

8
@ bflemi3 bạn đúng Boolà phụ thuộc, yêu cầu a Foovà lấy khóa ngoại. Foolà hiệu trưởng và có thể tồn tại mà không có a Boo.
Colin

182

Bạn cũng có thể sử dụng [Required]thuộc tính chú thích dữ liệu để giải quyết điều này:

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

Foolà cần thiết cho Boo.


Điều này đúng với mã sau đây của tôi, nơi tôi muốn có một bản đồ giữa hai người như một tổ chức lớp công khai thực thể riêng biệt {public int Id {get; bộ; }} người dùng lớp công khai {public int Id {get; bộ; }} Nhóm người dùng lớp công khai {[Key] public int Id {get; bộ; } [Bắt buộc] Tổ chức tổ chức ảo công khai {get; bộ; } [Bắt buộc] Người dùng ảo công khai {get; bộ; }}
AndyM

Tôi đang sử dụng Oracle và không ai trong số những người thông thạo làm việc cho tôi. Cảm ơn nhé người anh em. Quá đơn giản.
CameronP

11
Xin lưu ý rằng khi sử dụng giải pháp này, bạn sẽ nhận được các ngoại lệ xác thực khi bạn thử và cập nhật một Boocái mà bạn vừa lấy từ cơ sở dữ liệu, trừ khi trước tiên bạn kích hoạt tải lười biếng của thuộc Footính. entityframework.codeplex.com/SourceControl/network/fork/ từ
NathanAldenSr

2
Boo BooSau đó không nên ảo?
Simon_Weaver

1
@NathanAldenSr liên kết bây giờ rất tệ, làm thế nào để bạn thực hiện thay đổi đó?
CamHart

9

Điều này có liên quan đến câu trả lời của @Ladislav Mrnka về việc sử dụng api trôi chảy để cấu hình mối quan hệ một-một.

Có một tình huống mà FK of dependent must be it's PKkhông có khả thi.

Ví dụ, Foođã có mối quan hệ một-nhiều với 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;
}

Bây giờ, chúng tôi đã phải thêm một mối quan hệ một-một giữa Foo và 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;
}

Dưới đây là cách chỉ định mối quan hệ một-một bằng cách sử dụng api trôi chảy:

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

Lưu ý rằng trong khi thêm PrimaryBarIdcần phải được loại bỏ, vì chúng tôi chỉ định nó thông qua api trôi chảy.

Cũng lưu ý rằng tên phương thức [WithOptionalPrincipal()][1]là loại mỉa mai. Trong trường hợp này, Hiệu trưởng là Bar. Mô tả WithOptionalDeperee () trên msdn làm cho nó rõ ràng hơn.


2
Điều gì nếu bạn thực sự muốn các PrimaryBarIdbất động sản? Điều này là vô lý với tôi. Nếu tôi thêm tài sản và nói đó là khóa ngoại, tôi sẽ gặp lỗi. Nhưng nếu tôi không có tài sản, thì dù sao thì EF cũng sẽ tạo ra nó. Có gì khác biệt?
Chris Pratt

1
@ChrisPratt Điều này có vẻ không hợp lý. Tôi đã đến giải pháp này sau khi đường mòn và lỗi. Không thể định cấu hình ánh xạ một-một khi tôi có PrimayBarIdthuộc tính trong Foothực thể. Có khả năng cùng một giải pháp mà bạn đã thử. Hạn chế trong EF có lẽ?
Sudarshan_SMD

3
Vâng chính nó. Tôi đã phát hiện ra rằng EF cho đến ngày nay chưa bao giờ thực hiện các chỉ mục duy nhất. Kết quả là, cách duy nhất có sẵn để ánh xạ một-một là sử dụng khóa chính của đầu chính làm khóa chính của đầu phụ thuộc, bởi vì khóa chính là bản chất duy nhất. Nói cách khác, họ đã thực hiện một nửa và thực hiện một phím tắt chỉ ra rằng các bảng của bạn phải được thiết kế theo cách không chuẩn.
Chris Pratt
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.