#c# #entity-framework #ef-code-first #entity-framework-6
#c# #entity-framework #ef-code-first #entity-framework-6
Вопрос:
Сначала я использую код для генерации таблиц.
У меня есть пользовательский объект:
public class ApplicationUser
{
public int? ImageId { get; set; }
public virtual Image Image { get; set; }
public virtual ICollection<Image> Images { get; set; }
и изображение класса:
public class Image
{
public int ImageId { get; set; }
public int CreatedBy { get; set; }
public virtual ApplicationUser CreatedByUser { get; set; }
Я сопоставляю объекты с помощью fluent api:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// User can create many images
modelBuilder.Entity<Image>()
.HasRequired(e => e.CreatedByUser)
.WithMany(e => e.Images)
.HasForeignKey(e => e.CreatedBy)
.WillCascadeOnDelete(false);
// User can and doesn't have to have image
modelBuilder.Entity<ApplicationUser>()
.HasRequired(e => e.Image)
.WithOptional()
.WillCascadeOnDelete(false);
Первая часть создает мне одно отношение UserId > CreatedBy
нормально.
Но второе отношение — это 1:1
и связанные поля — это UserId > ImageId
то, чего я не пытаюсь добиться.
Я пытался использовать HasOptional
вместо HasRequired
этого, но тогда я получаю дополнительные ключи в таблицах.
Что я должен сделать, чтобы сопоставить эти две таблицы?
ОБНОВЛЕНИЕ 1
На основе ответа. Я оставляю User
и Image
классы одинаковыми.
У пользователя есть одно изображение (для профиля) и список изображений (все остальные изображения, созданные пользователем).
И я использую fluent api для соединения таблиц:
Но EF генерирует мне дополнительный ключ и не использует User > ImageId
в качестве ключа, я не могу понять, почему?
modelBuilder.Entity<ApplicationUser>()
.HasOptional(e => e.Image)
.WithOptionalDependent()
.WillCascadeOnDelete(false);
Ответ №1:
К сожалению, EF не поддерживает сопоставления 1: 1 таким образом. Если вы подумаете об этом, причина должна быть очевидна. Как бы вы смоделировали это в базе данных? Вы не можете. Лучшее, что вы можете сделать, это создать двойные соединения 1: много и many: 1.
т.е., если у вас есть две строки ApplicationUser, они обе могут иметь одинаковый ImageID. Нет способа гарантировать, что существует только одна строка (по крайней мере, не без ограничений, которые EF не поддерживает).
EF поддерживает только 1: 1 при использовании общего первичного ключа. Это означает, что обе сущности должны использовать одно и то же имя ключа, и они обе должны быть первичными ключами, и одна должна также сделать другую внешним ключом.
Комментарии:
1. Хммм… Можете ли вы предложить мне, как исправить мою модель? Пользователь может добавлять разные изображения, поэтому я должен был создать по полю (userId), и пользователь может, но не обязан, иметь ImageID (изображение профиля).
2. Ну, простой способ — просто сделать его равным 1: many и добавить только одно изображение… Более сложный способ заключается в том, что вы должны сделать так, чтобы ImageID имел тот же первичный ключ, что и ваш идентификатор пользователя, так же, как я объяснил выше, это должен быть внешний ключ в пользовательской таблице.
3. Этот вариант с тем же
PK
, что иImageId
в таблице изображений, невозможен, посколькуProfileImages{UserId, ImageId}
в таблице изображений автоматическое увеличение ghhh … Ок … так что я должен в принципе создать еще одну таблицу соединений, например: , , и когда пользователю нужно обновить изображение своего профиля, мне просто нужно обновить эту (соединительную) таблицу, верно?4. @1110 — Нет, это создало бы отношения «многие ко многим». 1: Много — это то, что вы хотите, в которое вы просто помещаете одно изображение. Создаете ли вы это значение 1: many из профиля или изображения, зависит от вас. Если бы это был я, и я знал, что вам никогда не понадобится больше одного изображения, то я бы поместил на изображение множество сторон, чтобы одна сторона была в профиле, чтобы упростить доступ к нему через навигационное свойство.
5. @1110 — Кстати, почему ImageID должен быть автоинкрементным? Вы, конечно, можете сделать так, чтобы это НЕ БЫЛО автоинкрементом.