Как определить EF code-first трехстороннее отношение FK?(родитель с двумя родственными детьми) - PullRequest
4 голосов
/ 28 февраля 2012

Я не уверен, как точно выразить, в чем заключается моя проблема, поэтому я просто углублюсь в то, что сделал, и опишу проблему по мере ее возникновения. Актуальный вопрос в конце поста.

Я использую EF 4.3 с первым кодом, и у меня есть общая сущность Category для организации различных типов контента:

public enum ContentType { Articles, Videos };

public class Category
{
    public long ID { get; set; }
    public long? ParentCategoryID { get; set; }

    internal int ContentTypeValue { get; set; }
    public string Title { get; set; }

    public virtual Category ParentCategory { get; set; }
    public virtual ICollection<Category> ChildCategories { get; set; }

    public ContentType ContentType
    {
        get { return (ContentType) ContentTypeValue; }
        set { ContentTypeValue = (int) value; }
    }
}

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

Map.Property( e => e.ContentTypeValue ).IsRequired().HasColumnName( "ContentType" );
Map.Property( e => e.Title ).IsRequired().HasMaxLength( 200 );

Map.HasOptional( e => e.ParentCategory ).WithMany( r => r.ChildCategories ).HasForeignKey( e => e.ParentCategoryID ).WillCascadeOnDelete( false );

Обратите внимание, что Category не предоставляет ссылки на другие типы объектов (кроме самого себя).

Затем я добавил сущность Article и отображение для нее:

public class Article
{
    public long ID { get; set; }
    public long CategoryID { get; set; }

    public string Title { get; set; }
    public string Body { get; set; }

    public virtual Category Category { get; set; }
}

Map.Property( e => e.Title ).IsRequired().HasMaxLength( 50 );
Map.Property( e => e.Body ).IsRequired().HasMaxLength( 4000 );
Map.HasRequired( e => e.Category ).WithMany().HasForeignKey( e => e.CategoryID ).WillCascadeOnDelete( false );

Это работает нормально и создает таблицу Article с PK (ID) и FK (CategoryID) для таблицы Category.

Следующим шагом было добавление аналогичного определения сущности и отображения для Видео, которое также работало как ожидалось.

public class Video
{
    public long ID { get; set; }
    public long CategoryID { get; set; }

    public string Title { get; set; }
    public string FileName { get; set; }

    public virtual Category Category { get; set; }
}

Map.Property( e => e.Title ).IsRequired().HasMaxLength( 50 );
Map.Property( e => e.FileName ).IsRequired().HasMaxLength( 200 );
Map.HasRequired( e => e.Category ).WithMany().HasForeignKey( e => e.CategoryID ).WillCascadeOnDelete( false );

Однако теперь я хотел бы, чтобы Article имела прямую ссылку на конкретное видео (независимо от того, к какой категории относится любая из них), поэтому, по сути, ссылка 1: 1 (обязательный: необязательный) между ними.

public class Article // broken
{
    public long ID { get; set; }
    public long CategoryID { get; set; }
    public long? VideoID { get; set; }

    public string Title { get; set; }
    public string Body { get; set; }

    public virtual Category Category { get; set; }
    public virtual Video Video { get; set; }
}

А для отображения класса я использовал бы следующее:

Map.Property( e => e.Title ).IsRequired().HasMaxLength( 50 );
Map.Property( e => e.Body ).IsRequired().HasMaxLength( 4000 );
Map.HasRequired( e => e.Category ).WithMany().HasForeignKey( e => e.CategoryID ).WillCascadeOnDelete( false );
Map.HasOptional( e => e.Video ).WithMany().HasForeignKey( e => e.VideoID ).WillCascadeOnDelete( false );

Как только я добавлю такую ​​ссылку, EF не сможет создать схему базы данных с DbUpdateException, сообщение об ошибке которого будет иметь вид "Невозможно определить основной конец (имя ограничения). У нескольких добавленных объектов могут быть одинаковые первичный ключ. "

Я могу решить эту проблему, не имея ссылку на видео категории (или не имея ссылки на статью видео, как показано в первом показанном коде), но это противоречит общей цели класса категории и вынудит меня поддерживать ArticleCategories, VideoCategories. и т. д.

Чтобы было совершенно ясно, что мне нужно, вот схема, которую я хотел бы закончить (обратите внимание: CategoryID в видео не должен быть обнуляемым, в отличие от изображения):

Database diagram

Как определить такое отношение, используя беглую нотацию в коде?

Ответы [ 2 ]

1 голос
/ 03 марта 2012

Я не могу воспроизвести проблему, ваши конфиги в порядке (я использую автоматические миграции здесь).

Можете ли вы добавить точную ошибку, которую она вам дает?

В любом случае, это мой точный код: https://gist.github.com/1961958

И это сгенерированный SQL из Update-Database: https://gist.github.com/1961961

РЕДАКТИРОВАТЬ: ops, я не увидел точно такой же ответ от @BalazsTihanyi, извините.

1 голос
/ 03 марта 2012

Странно, но у меня все это работает. Я не могу воспроизвести ошибку из представленного вами кода.
Что если вы попытаетесь воссоздать ваши таблицы из миграции 0?

...