Свойство внешнего ключа '' было создано в теневом состоянии из-за конфликтующего свойства с простым именем ''

Вся ошибка:

Свойство внешнего ключа «Appointment.CustomerId1» было создано в теневом состоянии, поскольку в типе объекта существует конфликтующее свойство с простым именем «CustomerId», но оно либо не сопоставлено, либо уже используется для другого отношения, либо несовместимо с соответствующий тип первичного ключа.

Таблицы:

Запись

Пользователь

В таблице назначений у меня было 2 FK: один указывал на таблицу клиентов (столбец идентификаторов), а другой - на таблицу сотрудников (столбец идентификаторов). Смотрите картинку в разделе ДО. Но теперь, поскольку у меня будут все пользователи (клиент + сотрудник) в одной таблице User, это должно измениться. Это означает, что в таблице назначений мне нужно иметь 2 FK, но оба должны указывать на одного и того же пользователя таблицы и столбец идентификатора. Я хочу, чтобы CustomerId и EmployeeId указывали на идентификатор пользователя.

Он создает 3 дополнительных столбца: UserId, CustomerId1 и EmployeeId1, которые мне не нужны. Я использовал только соглашения для отношений, никаких аннотаций данных или Fluent API.

Есть 3 вещи, которые могут вызвать ошибку:

    1. не нанесен на карту
    1. уже используется для других отношений
    1. несовместим с соответствующим типом первичного ключа

Насколько я понимаю

    1. это не мой случай, потому что тип данных тот же (строка).
    1. это не мой случай, потому что у меня нет других отношений.
    1. Может быть проблема, но я не уверен. Возможно, мне понадобится добавить Fluent API для этого сопоставления. Это то, что я пробовал, но это не работает: https://i.stack.imgur.com/UFrC6.png

Двунаправленный метод:

Класс пользователя:

public ICollection<Appointment> AppointmentCustomers { get; set; }
public ICollection<Appointment> AppointmentEmployees { get; set; }

Класс назначения:

public string CustomerId { get; set; }
[ForeignKey("CustomerId")]
public User Customer { get; set; }

public string EmployeeId { get; set; }
[ForeignKey("EmployeeId")]
public User Employee { get; set; }

Метод OnModelCreating:

builder.Entity<Appointment>()
    .HasOne(u => u.Customer)
    .WithMany(app => app.AppointmentCustomers)
    .HasForeignKey(u => u.CustomerId)
    .OnDelete(DeleteBehavior.NoAction);

builder.Entity<Appointment>()
    .HasOne(u => u.Employee)
    .WithMany(app => app.AppointmentEmployees)
    .HasForeignKey(u => u.EmployeeId)
    .OnDelete(DeleteBehavior.NoAction);

Что такое (1 конкретный исследованный не повторяющийся) вопрос? Как спросить Справочный центр

philipxy 18.11.2022 08:14

Пожалуйста, не вставляйте «EDIT»/«UPDATE», просто сделайте свой пост лучшей презентацией на момент редактирования. Пожалуйста, не повторяйте код в прозе. Пожалуйста, не включайте текст в изображения и не добавляйте лишние изображения.

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

Ответы 2

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

Раньше EF мог работать с ключами по соглашению. Соглашение основано на имени типа (сотрудник или клиент), а не на имени переменной. Если бы вы назвали FKs EmployeeKey/EmpID и CustomerKey/CustID, у вас возникла бы аналогичная проблема. Соглашение EF не связало бы их с FK, поэтому оно создало бы теневые свойства.

Теперь, когда вы указываете их обоих на один и тот же тип (пользователь), EF не может использовать соглашение, поэтому вы должны быть явными. Самый простой способ исправить это — использовать атрибут [ForeignKey]. Это можно либо поместить в свойство FK, чтобы указать на свойство навигации, либо в свойство навигации, чтобы указать на FK.

т.е.

[ForeignKey(nameof(Customer))]
public string CustomerId { get; set; }
[ForeignKey(nameof(Employee))]
public string EmployeeId { get; set; }

public virtual User Customer { get; set; }
public virtual User Employee { get; set; }

или

public string CustomerId { get; set; }
public string EmployeeId { get; set; }

[ForeignKey(nameof(CustomerId))]
public virtual User Customer { get; set; }
[ForeignKey(nameof(EmployeeId))]
public virtual User Employee { get; set; }

Редактировать:

Ошибка, которую вы сейчас получаете, связана с тем, что у пользователя есть коллекция встреч, но вам нужно указать EF, на какую коллекцию ссылается этот FK. Здесь у вас есть встреча, которая ссылается на двух пользователей, клиента и сотрудника. С точки зрения пользователя существует 2 различных отношения. Назначения-Я-Клиент и Назначения-Я-Сотрудник.

Если вас интересует только одно отношение, вам необходимо настроить EF для сопоставления User.Appointments на основе отношения «Назначение клиента» или «Сотрудник». Если вы заинтересованы в обоих, то у вас есть два варианта.

a) Добавьте 2 коллекции Appointments в User, т. е. AppointmentsAsCustomer и AppointmentsAsEmployee, и настройте сопоставления в ModelBuilder или EntityTypeConfiguration. б) Удалите коллекцию «Назначения» для пользователя и настройте EF с помощью .HasOne(x => x.Customer).WithMany() и .HasOne(x => x.Employee).WithMany(), а затем, когда вы хотите запросить встречи пользователя, сделайте это из «Встречи», а не ожидайте перехода через пользователя:

вместо того:

var appointmentsForUser = context.Users
    .Where(u => u.UserId == userId)
    .SelectMany(u => u.Appointments) // can't work for both asEmployee and asCustomer
    .ToList();

использовать:

var appointmentsForUser = context.Appointments
    .Where(a => a.Customer.UserId == userId 
       || a.Employee.UserId == userId) // if you want appts where user is customer or employee
    .ToList();

Двунаправленные ссылки (где Apointments ссылается на пользователей, а User ссылается на Appointments) следует использовать с осторожностью, только в случае крайней необходимости, а не по умолчанию. Они могут привести к странному поведению при обновлении, а также последствиям ленивой загрузки и подобным «подводным камням» с неоднозначными отношениями.

Здравствуйте и спасибо за быстрый и четкий ответ. Теперь я понимаю свою ошибку, имя важно. Однако я сделал то, что вы мне сказали, и попробовал оба ваших примера (даже если они одинаковы), и теперь, когда я пытаюсь добавить миграцию, у меня появляется эта новая ошибка: Невозможно определить отношение, представленное навигацией «Назначение. Клиент» типа «Пользователь». Либо вручную настройте связь, либо игнорируйте это свойство с помощью атрибута [NotMapped] или с помощью EntityTypeBuilder.Ignore в OnModelCreating. Я попытаюсь решить эту проблему, но вы хоть представляете, что это такое?

David Serb 10.11.2022 07:49

Я расширил ответ объяснением ошибки, которую вы теперь получаете, поскольку я пропустил, что у вас есть ссылка на коллекцию для назначений, объявленных в таблице пользователей, что вызовет проблемы.

Steve Py 10.11.2022 22:15

Привет, и извините за позднее обновление. а) Я добавил 2 новые коллекции в классе User: i.stack.imgur.com/o7t5Y.png Я настроил их с помощью FluentAPI в OnModelCreating with ModelBuilder: i.stack.imgur.com/MOgfr.png Я также изменил класс Appointment: i.stack.imgur.com/v2nTN.png b) Я удалил 2 новые коллекции Appointment из User. Я настроил их с помощью FluentAPI: i.stack.imgur.com/qRAxP.png И все. Что я делаю неправильно? Оба метода имеют одинаковую проблему (теневые свойства). Есть ли что-то, что EF перезаписывает...? Спасибо.

David Serb 17.11.2022 11:49

Похоже, вы не сделали то, что я указал в ответе. Когда у вас есть 2 или более ссылок из одной сущности на одну и ту же сущность (клиенты и сотрудники имеют тип пользователя), вы должны сообщить EF, какой внешний ключ использовать для каждой из них. Соглашение EF автоматически определяет FK, но делает это по имени типа, а не по имени свойства. Поэтому, если тип «Пользователь», он ожидает «UserId», вы должны указать ему использовать «CustomerId». Это можно сделать с помощью атрибута [ForeignKey] или с помощью .HasForeignKey() в ModelBuilder.

Steve Py 17.11.2022 22:58

Здравствуйте. Я так и сделал, если вы посмотрите на мою вторую картинку (i.stack.imgur.com/MOgfr.png). Существует .HasForeignKey(), и теперь я также использовал аннотацию данных: [ForeignKey(nameof(Customer))] для свойства CustomerId, и это все еще не работает. Я очень внимательно прочитал и следил за вашими комментариями и прочитал больше данных об этом, и я стараюсь изо всех сил, но я не могу понять, что я делаю неправильно с такой простой задачей.

David Serb 17.11.2022 23:10

То, что вы сделали, сбивает с толку, потому что последняя ссылка FluentAPI не имеет регистрации FK. Не видя реального кода, будет сложно увидеть полное состояние конфигурации и выявить проблемы. Это невозможно сделать с выборочными скриншотами. Рассмотрите возможность выделения только тех классов, свойств и конфигураций в отдельный проект, который воспроизводит проблему, и загрузите его на Github или вставьте код в вопрос. При решении проблем это помогает разбить все на минимальный воспроизводимый пример для работы.

Steve Py 18.11.2022 00:27

Я понимаю, ок. Я отредактировал свой вопрос, вы можете видеть это в разделе «Двунаправленный метод». Надеюсь, теперь мой код понятен и легко читается.

David Serb 18.11.2022 08:28

Свойство уже использовалось для другого отношения из старых классов Customer и Employee.

(Ответ Стива Пи очень помогает с настройками внешнего ключа, но из того, что я читал, лучше настраивать их с помощью Fluent API и аннотаций данных.)

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