Що означає головний кінець асоціації у співвідношенні 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

У відношенні один до одного один кінець повинен бути основним, а другий кінець повинен бути залежним. Головний кінець - це той, який буде вставлений перший і який може існувати без залежного. Залежний кінець - це той, який повинен бути вставлений після довірителя, оскільки він має зовнішній ключ до довірителя.

У випадку сутності ФК в залежності від ФК також повинен бути його ПК, тому у вашому випадку слід використовувати:

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, мені потрібно зробити дві незалежні таблиці, в яких обидві мають необов'язкове посилання один на одного (одна на одну), я хочу, щоб вони обоє мали свої ПК кожен, як це можливо? Я розмістив окреме запитання .
Шиммі Вайцхандлер

10
Ви не знаєте, скільки годин знадобилося, щоб знайти відповідь на це - мс документація POOOOOOP ty.
gangelo

1
Зауважте, що вам може знадобитися додати за допомогою System.ComponentModel.DataAnnotations.Schema; щоб отримати ForeignKey у VS2012
stuartdotnet

2
Це означає, що тоді Fooце головне?
bflemi3

8
@ bflemi3 ви правильні Boo- це залежний, вимагає Fooі отримує зовнішній ключ. 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; }
}

Fooпотрібно для Boo.


Це було правильним для мого наступного коду, де я хотів зробити карту між ними як окремий сукупність громадського класу Організація {public int Id {get; набір; }} користувач публічного класу {public int Id {get; набір; }} публічний клас UserGroup публічного класу {[Ключ] public int Id {get; набір; } [Обов’язкова] громадська віртуальна організація організації {get; набір; } [Обов’язковий] загальнодоступний віртуальний користувач {get; набір; }}
AndyM

Я використовую Oracle, і жодна з вільних api не працювала на мене. Дякую брате. Так просто.
CameronP

11
Майте на увазі, що при використанні цього рішення ви отримаєте винятки для перевірки, коли ви намагатиметесь і оновити файл, Booякий ви тільки що отримали з бази даних, якщо ви спочатку не запустили ледачий навантаження Fooресурсу. entitframework.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]є іронічною. У цьому випадку Основним є адвокатська колегія. Опис WithOtionalDependent () на msdn робить це більш зрозумілим.


2
Що робити , якщо ви на самому справі хочете в PrimaryBarIdвласність? Це для мене смішно. Якщо я додаю властивість і скажу, що це іноземний ключ, я отримаю помилку. Але якщо я не маю властивості, то EF все одно створить його. Яка різниця?
Кріс Пратт

1
@ChrisPratt Це може здатися розумним. Я прийшов до цього рішення після сліду та помилки. Не вдалося налаштувати відображення "один на один", коли я мав PrimayBarIdвластивість у Fooсутності. Ймовірно те саме рішення, що ви і ви пробували. Обмеження в EF, можливо?
Sudarshan_SMD

3
Так, це так. Я з'ясував, що EF до цього часу ніколи не реалізовував унікальні індекси. Як результат, єдиний доступний спосіб зіставити один-на-один - використовувати первинний ключ головного кінця як первинний ключ залежного кінця, оскільки первинний ключ за своєю природою унікальний. Іншими словами, вони наполовину реалізували це та взяли ярлик, який наказує, що ваші таблиці повинні бути спроектовані нестандартно.
Кріс Пратт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.