Добавление второй связи «один к одному» с той же таблицей в структуре сущностей

Я занимаюсь проектированием инфраструктуры сущностей с кодом.

У меня есть таблица Account, в которой есть свойство Supervisor:

public class Account
{
  public int Id { get; set; }
  public Account Supervisor { get; set; }
}

Это прекрасно работает.

Однако я хочу добавить в класс альтернативного руководителя:

public class Account
{
  public int Id { get; set; }
  public Account Supervisor { get; set; }
  public Account AlternateSupervisor { get; set; }
}

Когда я запускаю Add-Migration AddAlternateSupervisor, сгенерированный код дает мне следующее:

public partial class AddAlternateSupervisor : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropForeignKey(
            name: "FK_Accounts_Accounts_SupervisorId",
            table: "Accounts");

        migrationBuilder.DropIndex(
            name: "IX_Accounts_SupervisorId",
            table: "Accounts");

        migrationBuilder.AddColumn<int>(
            name: "AlternateSupervisorId",
            table: "Accounts",
            nullable: true);

        migrationBuilder.CreateIndex(
            name: "IX_Accounts_AlternateSupervisorId",
            table: "Accounts",
            column: "AlternateSupervisorId",
            unique: true,
            filter: "[AlternateSupervisorId] IS NOT NULL");

        migrationBuilder.AddForeignKey(
            name: "FK_Accounts_Accounts_AlternateSupervisorId",
            table: "Accounts",
            column: "AlternateSupervisorId",
            principalTable: "Accounts",
            principalColumn: "Id",
            onDelete: ReferentialAction.Restrict);
    }
    // snip
}

Как видите, EF пытается переименовать мою ссылку с Supervisor на AlternateSupervisor. Я не хочу этого, я хочу, чтобы и Supervisor, и AlternateSupervisor ссылались на другие учетные записи.

Я знаю, что EF не может обрабатывать несколько отношений «многие ко многим», но это отношения «один к одному». Кажется, я не могу найти никакой информации о том, почему EF генерирует такую ​​миграцию.

Итак, почему Entity Framework пытается переименовать Supervisor в AlternateSupervisor и как я могу заставить его генерировать обе ссылки?

Обновлено: на этот вопрос был дан ответ, заданный изначально. Тем не менее, я хотел бы добавить, что заданный вопрос на самом деле не имеет большого смысла в предметной области. Кто когда-либо слышал об учетной записи, которая могла контролировать ровно одну другую учетную запись? Отношение представляет собой отношение «один ко многим», которое разрешается путем использования WithMany вместо WithOne.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
2 709
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

EF Core не может сопоставлять несколько one-to-one с одним и тем же объектом по соглашению. Вы должны сделать это с Fluent API следующим образом:

Ваш Account класс:

public class Account
{
    public int Id { get; set; }

    public int SupervisorId { get; set; }
    public Account Supervisor { get; set; }

    public int AlternateSupervisorId { get; set; }
    public Account AlternateSupervisor { get; set; }
}

Затем в OnModelCreating из DbContext следующим образом:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
     base.OnModelCreating(modelBuilder);

     modelBuilder.Entity<Account>().HasOne(a => a.Supervisor).WithOne()
            .HasForeignKey<Account>(a => a.SupervisorId).OnDelete(DeleteBehavior.Restrict);

      modelBuilder.Entity<Account>().HasOne(a => a.AlternateSupervisor).WithOne()
            .HasForeignKey<Account>(a => a.AlternateSupervisorId).OnDelete(DeleteBehavior.Restrict);
 }

Теперь все будет генерироваться, как и ожидалось!

Примечание. Я добавил внешний ключ SupervisorId и AlternateSupervisorId явно в класс модели Account для удобочитаемости. Если вы не хотите этого явно, тогда конфигурация Fluent API должна быть следующей:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
     base.OnModelCreating(modelBuilder);

     modelBuilder.Entity<Account>().HasOne(a => a.Supervisor)
                  .WithOne().OnDelete(DeleteBehavior.Restrict);

      modelBuilder.Entity<Account>().HasOne(a => a.AlternateSupervisor)
                  .WithOne().OnDelete(DeleteBehavior.Restrict);
 }

Спасибо. Это работает. Я не уверен, что на 100% понимаю, почему это необходимо или почему это работает. В классе Account нужно пометить int как целое, допускающее значение NULL, если супервизор или альтернативный супервизор не является обязательным.

Stephen 20.03.2019 03:09

Да! Ты прав. Потому что без этого нельзя вставить исходные данные. :)

TanvirArjel 20.03.2019 03:10

На самом деле я понял, что в любом случае мне нужно что-то немного другое, поскольку на самом деле я не хочу отношений один к одному, поскольку один супервайзер может контролировать множество учетных записей, но вы ответили на мой вопрос именно так, как он был задан, так что слава!

Stephen 20.03.2019 03:13

Другие вопросы по теме