Модель EF Core не может выполнить миграцию из-за того, что PrimaryKey ссылается на ForeignKey

В настоящее время я получаю следующую ошибку во время dotnet ef migrations add Initial

Невозможно создать «DbContext» типа «».

Исключение «Свойство TestChild.Parent» TestChild.Parent не удалось сопоставить, поскольку поставщик базы данных не поддерживает этот тип.
Рассмотрите возможность преобразования значения свойства в тип, поддерживаемый базой данных, с помощью преобразователя значений.
См. https://aka.ms/efcore-docs-value-converters для получения дополнительной информации.
Альтернативно исключите свойство из модели, используя атрибут «[NotMapped]» или используя «EntityTypeBuilder.Ignore» в «OnModelCreating». был выброшен при попытке создать экземпляр. Информацию о различных шаблонах, поддерживаемых во время разработки, см. https://go.microsoft.com/fwlink/?linkid=851728

Моя минимальная модель выглядит так:

public class RecipeContext : DbContext
{
    public DbSet<TestParent> Parents { get; set; }

    public RecipeContext(DbContextOptions<RecipeContext> options)
    : base(options)  {  }
}

[PrimaryKey(nameof(Name))]
public class TestParent
{
    [Required]
    public string Name { get; set; }

    public virtual ICollection<TestChild> Children { get; set; }
}

[PrimaryKey(nameof(Parent))]
public class TestChild
{
    [Required]
    public virtual TestParent Parent { get; set; }
}

В реальном мире TestChild имеет составной первичный ключ, поэтому он имеет немного больше смысла, чем этот минимальный пример.

Я пробовал это как с поставщиками Sqlite, так и с SQL Server, оба выдают одинаковые ошибки, что заставляет меня полагать, что это не относится к одному поставщику, а вместо этого является либо «ошибкой» в EF Core (v8.0.4), либо чем-то еще. вероятно, какое-то недопонимание того, как навигационные связи/атрибуты внешнего ключа в EF Core работают вместе.

Пока у меня нет элемента навигации/внешнего ключа (Parent) в атрибуте PrimaryKey для класса TestChild, это работает. например если я добавлю еще один столбец, например Id, к TestChild и буду использовать именно этот столбец в качестве PrimaryKey для TestChild, это будет работать.

Однако на самом деле это не соответствует тому ограничению уникальности, которое мне хотелось бы. Для каждого Parent может быть только один Child с тем же именем (поэтому в реальном мире мне нужен PrimaryKey(nameof(Parent),nameof(Name)).

Любое руководство по этому поводу было бы здорово. Возможно, есть документ EF Core, который точно описывает то, что я хочу (и как я делаю это неправильно)?

ПК не может быть свойством навигации. Если у дочернего элемента есть составной ключ ParentName и какого-либо другого столбца, вам необходимо объявить составной ключ, например [PrimaryKey("ParentName","OtherColumn")]

Steve Py 10.04.2024 07:29
Стоит ли изучать 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
1
161
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

EF Core работает на основе соглашений по умолчанию и не может понять ваши текущие настройки. По умолчанию EF Core сгенерирует теневой FK для вашей настройки (ParentName, но обратите внимание, что соглашения могут меняться в зависимости от версии и настройки), и вам необходимо указать его имя для использования в качестве PK (а не имя свойства навигации). Например, для моей минимальной настройки с SQLite работает следующее:

[PrimaryKey("ParentName")]
public class TestChild
{   
    [Required]
    public virtual TestParent Parent { get; set; }
}

Или вы можете явно объявить ключ свойства навигации:

[PrimaryKey(nameof(ParentName))]
public class TestChild
{
    public string ParentName { get; set; }
    
    [Required]
    [ForeignKey(nameof(ParentName))]
    public virtual TestParent Parent { get; set; }
}

Смотрите также:

Более явное использование теневых свойств внешнего ключа действительно помогло. Спасибо. Однако я до сих пор не совсем понимаю, почему это не учтено «конвенциями». Разве свойство навигации уже не подразумевает использование внешнего ключа (и, следовательно, теневых свойств для отношений FK)? Таким образом, использование свойства навигации в атрибуте PrimaryKey() дочернего элемента должно просто «расширяться» до названных свойств тени внешнего ключа.

BevanWeiss 11.04.2024 03:04

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