Требует ли EF 6, чтобы внешний ключ имел имя, отражающее имя внешней таблицы?

#c# #entity-framework #ef-code-first

Вопрос:

Сначала мы работаем с кодом EF 6 с существующей базой данных. Мы работаем с SQL Server, мой босс создает таблицы с помощью сценариев SQL, сгенерированных из TOAD. Обычно таблицы создаются по этому шаблону:

  • Имя таблицы: например: Персона
  • Первичный ключ: идентификатор (это ВСЕГДА просто идентификатор)

И обычно при создании таблицы, которая имеет отношение 1 к 1 или 1 или ноль с другой таблицей, она создается с использованием этого шаблона:

  • Название таблицы: Адрес
  • Первичный ключ: ИДЕНТИФИКАТОР
  • Внешний ключ для человека: PersonID

Однако мой босс нарушил свой шаблон с двумя столами, и это причиняет мне много горя. Я думаю, что это потому, что он назвал внешний ключ чем-то, что не соответствует шаблону, он используется везде. Но я могу ошибаться. Конечно, мне не кажется, что код EF сначала с существующей базой данных распознает связь. Вот фрагмент SQL для двух таблиц, которые вызывают проблемы (я удаляю столбцы, которые не имеют отношения к делу):

 CREATE TABLE [app].[PersonnelCertification]
(
 [ID] Bigint IDENTITY NOT NULL,
 [CertificationTypeID] Bigint NOT NULL,
 [InstrumentModelID] Bigint NOT NULL,
 [PersonID] Bigint NOT NULL,
 [AgencyID] Bigint NOT NULL,
 [CertificationLevelID] Bigint NOT NULL,
)
 

Вот фрагмент SQL-кода в таблице навыков:

 CREATE TABLE [app].[Proficiency]
(
 [ID] Bigint IDENTITY(1,1) NOT NULL,
 [PersonCertID] Bigint NOT NULL,
 [InstrumentID] Bigint NULL,
 [SolutionID] Bigint NOT NULL,
)

ALTER TABLE [app].[Proficiency] ADD CONSTRAINT [PersonnelCertification-Proficiency] FOREIGN KEY ([PersonCertID]) REFERENCES [app].[PersonnelCertification] ([ID]) ON UPDATE NO ACTION ON DELETE NO ACTION
go

ALTER TABLE [app].[Proficiency] ADD CONSTRAINT [Solution-Proficiency] FOREIGN KEY ([SolutionID]) REFERENCES [app].[Solution] ([ID]) ON UPDATE NO ACTION ON DELETE NO ACTION
go

ALTER TABLE [app].[Proficiency] ADD CONSTRAINT [Instrument-Proficiency] FOREIGN KEY ([InstrumentID]) REFERENCES [app].[Instrument] ([ID]) ON UPDATE NO ACTION ON DELETE NO ACTION
go
 

А вот результирующий код, сгенерированный первым кодом с существующей базой данных, для таблицы навыков:

 [Table("app.Proficiency")]
public partial class Proficiency
{
    public long ID { get; set; }

    public long PersonCertID { get; set; }

    public long? InstrumentID { get; set; }

    public long SolutionID { get; set; }

    public virtual Instrument Instrument { get; set; }

    public virtual Solution Solution { get; set; }
}
 

Есть таблица с именем «Решение«, которая связана с квалификацией. Там есть таблица с именем Инструмент, относящаяся к мастерству. В сгенерированном классе модели квалификации нет ничего, связанного с аттестацией персонала. И, как я уже сказал, нет таблицы с именем PersonCert.

Я не знаю, как решить эту проблему. Я попытался добавить [ForeignKey] атрибут в PersonCertID, но это не сработало. Я также попытался добавить некоторый код в класс, сгенерированный DbContext, для определения связи между двумя таблицами, которые код сначала с существующими базами данных не распознает, но я не смог обнаружить, что будет работать. Я был бы признателен за информацию о том, использует ли EF 6 что-то вроде соглашения по конфигурации для определения взаимосвязей внешних ключей. Например, было бы лучше, если бы PersonCertID был переименован в PersonnelCertificationID? Или есть способ указать API Fuild в DbContext, чтобы объявить эту взаимосвязь между квалификацией и аттестацией персонала?

Комментарии:

1. Имя внешнего ключа на стороне базы данных не имеет никакого отношения к тому, как EF связывает сущности

2. Почему бы просто не заставить своего босса следовать шаблону, используемому везде, чтобы вы могли скопировать шаблон кода EF, который вы используете везде? Или еще лучше заставить босса отказаться от разработки программного обеспечения и сосредоточиться на своей роли (владелец продукта, развитие бизнеса, что угодно — они дают спецификации функций, которые им нужны, и оставляют реализацию инженерам).

3. вы используете сначала код или конструктор EF?

4. Вам нужно много слов, чтобы сказать, что вы не знаете, как отображать отношения в EF, когда соглашения об именах не делают этого за вас. Все это хорошо задокументировано, например docs.microsoft.com/en-us/ef/ef6/modeling/code-first/fluent/.

5. Можете ли вы обновить вопрос полным набором DDL, который воспроизводит проблему? АФАИК, это должно сработать нормально. Но, как указывает @GertArnold, вы всегда можете просто написать классы и сопоставить их с таблицами вручную.

Ответ №1:

Надеюсь, где-нибудь у вас class PersonnelCertification будет возможность изменить свое мастерство, например:

 Table("app.Proficiency")]
public partial class Proficiency
{
    public long ID { get; set; }

    [ForeignKey(nameof(PersonnelCertification))]
    public long PersonCertID { get; set; }
    public virtual PersonnelCertification PersonnelCertification { get; set; }

    public long? InstrumentID { get; set; }
 

Или вы могли бы это изменить:

 public partial class Proficiency
{
    public long ID { get; set; }

    
    public long PersonCertID { get; set; }
    [ForeignKey(nameof(PersonCertID))]
    public virtual PersonnelCertification PersonnelCertification { get; set; }

    public long? InstrumentID { get; set; }
 

Или вы можете изменить аттестацию персонала:

 class PersonnelCertification{

    ...
    
    [ForeignKey(nameof(Proficiency.PersonCertID))]
    public ICollection<Proficiency> Proficiencies
 

Используйте то, что больше всего соответствует вашему чувству связывания этих вещей воедино. Мне нравится вариант 2

Обратите внимание, что компилятор превращает nameof в строку; он принимает » вещь «C# (класс, метод, свойство и т. Д.) Или «путь к вещи» и дает строковое имя вещи. Это полезно, потому что это означает, что intellisense поможет вам написать эту вещь, и если вы когда-нибудь переименуете ее с помощью встроенных инструментов рефакторинга, она обновится там, где строка не будет