#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), уникальны среди всех строк в таблице.