Проблема с EF CF и существующей связью «один к одному»

Я использую существующую базу данных с EF Code First и использую modelBuilder для настройки. У меня есть две таблицы, в которых SESSION может иметь SUBJECT, классы как таковые:

public class SessionItem {
   [Key]
   public int SessionId { get;set; }
   // Other Values
   public int Subject_ID { get;set; }

   public virtual Subject Subject { get;set; }
}

public class SubjectItem {
   [Key]
   public int Subject_ID { get;set; }
   // Other Values

   public virtual SessionItem Session { get;set; }
}

И тогда код modelBuilder:

modelBuilder.Entity<SessionItem>().ToTable("tblTblSessions");
modelBuilder.Entity<Subject>().ToTable("tblTblSubjects");
modelBuilder.Entity<SessionItem>()
   .HasOptional<Subject>(u => u.Subject)                     
   .WithOptionalDependent(c => c.Session).Map(p => p.MapKey("Subject_ID"));

Сначала это не удалось, пока я не удалил Subject_ID из класса SessionItem, затем я получил ошибку: Произошло нарушение ограничения множественности отношения: EntityReference может иметь не более одного связанного объекта, но запрос вернул более одного связанного объекта. Это неисправимая ошибка.

Есть идеи, где я ошибся?


person user1166905    schedule 23.07.2012    source источник
comment
Столбец Subject_ID не уникален в базе данных или почему запрос возвращает более одного связанного объекта? Вы действительно хотите отношений один-к-одному или один-ко-многим?   -  person Slauma    schedule 23.07.2012
comment
Он уникален, по существу есть список тем и каждая сессия может иметь одну тему. У меня может быть совершенно неправильный код modelBuilder, я новичок в его использовании!   -  person user1166905    schedule 23.07.2012
comment
Аналогичный вопрос: stackoverflow.com/q/3622572/176877   -  person Chris Moschini    schedule 30.03.2013


Ответы (3)


person Slauma    schedule 23.07.2012
comment
Это было то, что я сделал, чтобы заставить его работать, я удалил свойство навигации в теме, так как эта ссылка не требовалась. Не уверен, почему это не появилось, прежде чем я разместил свое исправление выше. - person user1166905; 23.07.2012

Попробуй это:

public class SessionItem 
{
   [Key]
   public int SessionId { get;set; }
   // Other Values
   [ForeignKey("Subject")]
   public int? Subject_ID { get;set; }

   [ForeignKey("Subject_ID")]    
   public virtual SubjectItem Subject { get;set; }
}

Вам нужно сделать внешний ключ Subject_ID обнуляемым.

person Paul Fleming    schedule 23.07.2012
comment
Нужна ли мне моя ссылка в modelBuilder или удалить ее? - person user1166905; 23.07.2012
comment
@user1166905. Используйте либо. Важным моментом является обнуляемый идентификатор public int? Subject_ID - person Paul Fleming; 23.07.2012
comment
Удалив код modelBuilder, который пытается сделать ссылку, и используя вышеизложенное, я получил следующее: Множественность недействительна в роли «SessionItem_Subject_Source» в отношении «SessionItem_Subject». Поскольку свойства зависимой роли не являются ключевыми свойствами, верхняя граница кратности зависимой роли должна быть '*'. - person user1166905; 23.07.2012
comment
Я изменил класс Subject, чтобы сделать сеансы ICollection, а затем добавил в modelBuilder следующее: e => e.Subject_ID); Теперь это передается предыдущей ошибке, но происходит неправильная загрузка сеансов в теме (вероятно, из-за того, что есть 0000) - person user1166905; 23.07.2012
comment
Я удалил навигацию из темы и поставил: Теперь он работает нормально - person user1166905; 23.07.2012
comment
+1 за справедливость, так как ваш код уже был на 50% решением. - person Slauma; 23.07.2012

[Table("tblTblSessions")]
public class SessionItem {
    [Key]
    public int SessionId { get; set; }

    public virtual SubjectItem Subject { get; set; }
}

[Table("tblTblSubjects")]
public class SubjectItem {
    [Key, ForeignKey("Session")]
    public int Subject_ID { get; set; }

    public virtual SessionItem Session { get; set; }
}

Отношение один к одному между SubjectItem и SessionItem, и вы можете избавиться от всего вашего кода modelBuilder - все имена таблиц и сопоставление один к одному, которые вы делали, позаботятся о атрибутах и ​​​​свойствах выше.

Редактировать: исправлена ​​опечатка и отмечена зависимая сторона один к одному.

person Chris Moschini    schedule 30.03.2013
comment
Вы проверили это? Я сделал. Во-первых: он не компилируется. Во-вторых: если вы исправите очевидную ошибку, чтобы заставить ее компилироваться (public virtual SubjectItem Subject { get; set; }), она выдает исключение, что кратность на одном конце должна быть * (много). Причина, как я уже сказал: ассоциации внешних ключей «один к одному» не поддерживаются EF. - person Slauma; 30.03.2013
comment
@Slauma У меня есть собственный код с похожими моделями доменов, но с разными именами, поэтому прошу прощения за опечатку (и, возможно, вам следует извиниться за свой тон). Я добавил вышеуказанные классы в тестовый проект и обновил приведенный выше пример. - person Chris Moschini; 31.03.2013
comment
+1, потому что теперь это работает после исправления :) Но это общая ассоциация первичного ключа. Кто знает, достаточно ли этого для ОП. Общие первичные ключи более ограничены, чем однозначные ассоциации FK (например, вы не можете назначить Subject другому Session, только тому, который имеет тот же ключ), и то, что он, похоже, пытался в этом вопросе, является FK -к одному. О тоне: Что вы ожидаете? Вы пишете ложное утверждение под моим ответом, ставите минус на основании этого, а затем пишете неправильный ответ. То, что он не скомпилировался, было педантичным, важен был только пункт 2. Я был зол, извините... - person Slauma; 31.03.2013
comment
Кстати: тот факт, что EF не поддерживает взаимно-однозначные связи внешнего ключа, является лишь следствием того факта, что он не поддерживает ограничения уникального ключа (и по-прежнему не будет в EF 6), что действительно очень большой ограничение и номер 3 в списке наиболее востребованных функций: key-support" rel="nofollow noreferrer">data.uservoice.com/forums/ - person Slauma; 31.03.2013
comment
@Slauma Отлично, спасибо, что помогли мне улучшить ответ. Я здесь немного в затруднительном положении, потому что мы создаем приложения с нуля, где нам не нужно охватывать существующие базы данных, поэтому отсутствие поддержки этого конкретного способа обработки один к одному не влияет на нас. Тем не менее, даже работа с существующей базой данных должна быть возможной путем копирования данных в таблицы, подходящие для EF, без потери данных, поэтому я понимаю, почему эта функция могла оставаться с низким приоритетом в Microsoft. - person Chris Moschini; 31.03.2013
comment
Ну, это не столько вопрос существующих или новых баз данных, сколько бизнес-требований. Общие ассоциации первичных ключей более специфичны и ограничены (делают отношения неизменяемыми). На самом деле они представляют собой особый случай однозначных ассоциаций внешнего ключа (= FK с уникальным ограничением), а именно особый случай, когда FK идентичен PK зависимого. - person Slauma; 31.03.2013
comment
@Slauma Ну, один бизнес-кейс, который я не могу решить с помощью EF, - это тот, в котором у меня есть 1: 1 обе стороны необязательно (поскольку общий ПК требует зависимых отношений); У меня есть несколько из них в развернутых приложениях, которые я решаю, не имея никаких ограничений FK. Я по-прежнему могу легко запрашивать и присоединять их, и во многих случаях это может упростить удаление из-за меньшего количества зависимостей/каскадов, о которых нужно беспокоиться. - person Chris Moschini; 31.03.2013