Моделирование данных Entity Framework: 2 внешних ключа и первичный ключ

#c# #asp.net-mvc #entity-framework #npgsql #composite-primary-key

#c# #asp.net-mvc #entity-framework #npgsql #составной первичный ключ

Вопрос:

У меня есть следующие таблицы:

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

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

public class Registration{
  public int Id {get;set;}
  public int EventId {get;set;}
  public int PaticipantId {get;set;}
}
  

У меня есть идентификатор регистрации в качестве первичного ключа, но как мне убедиться, что eventid и particpantid уникальны? Я думал о составном ключе, но мне нужно было свойство Id при регистрации, так как оно понадобится мне в качестве внешнего ключа в другом классе / таблице.

для тех, кто интересуется моим dbcontext, это выглядит так:

 modelBuilder.Entity<Registration>()
                .HasRequired(e => e.Participant)
                .WithMany(u => u.Events)
                .HasForeignKey(e => e.ParticipantId);

            modelBuilder.Entity<Registration>()
                .HasRequired(e => e.Event)
                .WithMany(u => u.Participants)
                .HasForeignKey(e => e.EventId);
  

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

1. вы хотите, чтобы комбинация EventID и participantId была уникальной? Уникальный ключ для этих двух столбцов в базе данных гарантирует это, или это не то, что вы просили?

2. вы говорите о составных ключах? я думал об этом, но мне нужен отдельный уникальный идентификатор, помимо их комбинации в качестве идентификатора. вот что такое регистрация. Идентификатор предназначен для. Но мне нужно убедиться, что идентификатор события и идентификатор участника уникальны.

3. Ну, ваш регистрационный идентификатор — это ваш первичный ключ. По умолчанию postgres создает уникальное ограничение для этого столбца. Затем вы добавляете уникальный ключ в столбцы EventID и ParticipantId поверх этого (в вашей базе данных postgresql.org/docs/9.6/static/indexes-unique.html . Таким образом, ваш регистрационный идентификатор уникален, а комбинация EventID, ParticipantId также уникальна. Если вы используете миграции entity Framework, вы можете указать в своем классе dbcontext, что вам нужен уникальный ключ для этих двух столбцов, и позволить Entity Framework сгенерировать миграцию для вас (или добавить их вручную в миграцию)

4. как мне получить созданный идентификатор? Мне понадобится этот идентификатор для связи «многие ко многим» с другой таблицей

5. Для отношений «многие ко многим» в вашей регистрационной таблице вы используете свой первичный ключ (Id), для этого нет необходимости в дополнительном идентификаторе… ваш уникальный ключ предотвратит дублирование записей в вашей регистрационной таблице, и вы не будете использовать его для таблиц, ссылающихся на вашу регистрационную таблицу, для этого вы должны использовать первичный ключ (Id)

Ответ №1:

Создайте другую таблицу, содержащую EventID и PaticipantId в качестве составного ключа, затем поместите этот идентификатор таблицы в вашу регистрационную таблицу.

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

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

public class NewTable{
   public int Id {get;set;}
   public int EventId  {get;set;}
   public int PaticipantId {get;set;}
}

public class Registration{
  public int Id {get;set;}
  public int NewTableId {get;set;}
}
  

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

1. вы имели в виду иметь идентификатор в новой таблице? похоже, что таблица регистрации уже есть, если вы это сделаете. Мне понадобится, чтобы новая таблица имела уникальную комбинацию идентификаторов события и участника. Допустим, что новая таблица — это то, что она есть. Как мне создать этот составной ключ с идентификатором, который будет увеличивать каждую вставку?

2. зачем вам нужно, чтобы идентификатор регистрационной таблицы стал первичным ключом, потому что он будет увеличиваться каждый раз?

3. да, мне это понадобится и для связи «многие ко многим» с другой таблицей

4. для этого не обязательно быть первичным ключом.

5. Понятно, так как же мне тогда сделать это в моем классе? просто сделайте составной ключ для eventid и participantid, а затем для свойства id, как мне сделать так, чтобы база данных обновлялась последовательностью? кстати, я делаю этот codefirst и просто обновляю таблицу с помощью миграции сущностей

Ответ №2:

На самом деле существует МНОЖЕСТВО способов убедиться, что комбинация EventID и PaticipantId уникальна, даже не касаясь вашей модели.

Это можно установить в вашей БД: вы можете объявить комбинацию из двух полей УНИКАЛЬНОЙ, а затем перехватить ошибку внутри вашего приложения и обработать ее так, как вы хотите.

Вы также можете выполнить проверку непосредственно внутри своего приложения с помощью функции, которая проверяет, существует ли комбинация. (возвращает false, если он существует)

Вы также можете добавить в свою модель ДРУГОЕ поле, строку, представляющую оба идентификатора в одних и тех же полях, и объявить его уникальным

На самом деле, для вашей проблемы есть множество решений… Выберите то, что проще для себя.

Ответ №3:

Вы должны добавить уникальный ключ в комбинацию столбцов EventID и ParticipantId

Поскольку вы используете миграции EF, вы можете добавить уникальный ключ в свою модель и позволить Entity Framework впоследствии сгенерировать для вас новую миграцию. Затем эта миграция добавит уникальный ключ в вашу базу данных. В зависимости от вашей версии Entity Framework это будет отличаться.

В Entity Framework Core 1.0.0 это просто:

 modelBuilder.Entity<Registration>().HasIndex(x => new { x.ParticipantId, x.EventId}).IsUnique();
  

При использовании Entity Framework 6 вы можете использовать аннотации или fluent api (хотя и довольно подробный):

С аннотациями:

 public class Registration
{
  public int Id {get;set;}
  [Index("UQ_Registration_EventId_ParticipantId", 1, IsUnique = true)]
  public int EventId {get;set;}
  [Index("UQ_Registration_EventId_ParticipantId", 2, IsUnique = true)]
  public int PaticipantId {get;set;}
}
  

Или с помощью fluent API:

 string uniqueIndex = "UQ_Registration_EventId_ParticipantId";

modelBuilder.Entity<Registration>().Property(t => t.EventId)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName,
        new IndexAnnotation(
            new IndexAttribute(uniqueIndex)
            {
                IsUnique = true,
                Order = 1
            }
        )
    );

modelBuilder.Entity<Registration>().Property(t => t.ParticipantId)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName,
        new IndexAnnotation(
            new IndexAttribute(uniqueIndex)
            {
                IsUnique = true,
                Order = 2
            }
        )
    );
  

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

1. хорошо, это кажется простым, один вопрос, uniqueIndex, это то, что мне нужно сгенерировать самостоятельно? кроме того, будет ли автоматически сгенерирован идентификатор?

2. Автоматически сгенерированный идентификатор отсутствует. Уникальный ключ — это всего лишь ограничение, запрещающее появление в таблице повторяющихся комбинаций EventID и ParticipantId. У него нет самого идентификатора. Уникальные ограничения гарантируют, что данные, содержащиеся в столбце или группе столбцов (в данном случае ваши два идентификатора внешнего ключа EventID и ParticipantId), уникальны среди всех строк в таблице.