EF Code First: нарушение ограничения множественности

ПОМОЩЬ! – Я получаю следующую ошибку в моей навигационной модели ArticleType:

Произошло нарушение ограничения множественности отношения

Вот существующая схема базы данных:

модель базы данных

Вот мой код:

public class Article
{
    public int ID { get; set; }
    public virtual Stage Stage { get; set; }
    public virtual ArticleType ArticleType { get; set; } // Causes the violation
}

public class ArticleType
{
    public int ID { get; set; }
    public string Title { get; set; }
}

public class Stage
{
    public int ID { get; set; }
    public string Title { get; set; }
}

Я использую свободный API для своего отображения, вот выдержка из ассоциации

// This works
modelBuilder.Entity<Article>
    .HasRequired(t => t.Stage)
    .WithMany() // if turned .WithOptional() then will also cause the error.
    .Map(m => m.MapKey("stage_id"));

// This does not work
modelBuilder.Entity<Article>
    .HasRequired(t => t.ArticleType)
    .WithMany()
    .Map(m => m.MapKey("article_type_id"));

Моя проблема заключается в том, почему ArticleType вызывает ошибку, а Stage — нет, даже если объявление и сопоставление синтаксически одинаковы?

ИЗМЕНИТЬ 1

Я узнал об исключении, изучив объект статьи, наведя указатель мыши (не уверен, что это точный термин)

открыть изображение на новой вкладке

Сведения об ошибке

System.InvalidOperationException was unhandled by user code
  HResult=-2146233079
  Message=A relationship multiplicity constraint violation occurred: An EntityReference can have no more than one related object, but the query returned more than one related object. This is a non-recoverable error.
  Source=System.Data.Entity
  StackTrace:
       at System.Data.Objects.DataClasses.EntityReference`1.Load(MergeOption mergeOption)
       at System.Data.Objects.DataClasses.RelatedEnd.Load()
       at System.Data.Objects.DataClasses.RelatedEnd.DeferredLoad()
       at System.Data.Objects.Internal.LazyLoadBehavior.LoadProperty[TItem](TItem propertyValue, String relationshipName, String targetRoleName, Boolean mustBeNull, Object wrapperObject)
       at System.Data.Objects.Internal.LazyLoadBehavior.<>c__DisplayClass7`2.<GetInterceptorDelegate>b__2(TProxy proxy, TItem item)
       at System.Data.Entity.DynamicProxies.Package_A18FADC105CCF13C9CD346622D43BD35514E489CCC1E5B1E4A3C78806BDCA0F5.get_ArticleType()
       at AuthorProofing.Service.ReminderService.DeliverDailyReminders() in C:\Users\default.Lenovo-PC\Documents\Visual Studio 2010\Projects\AuthorProofing\AuthorProofing.Service\ReminderService.cs:line 36
       at AuthorProofing.Tests.ReminderServiceTest.DeliverDailyRemindersTest() in C:\Users\default.Lenovo-PC\Documents\Visual Studio 2010\Projects\AuthorProofing\AuthorProofing.Tests\ReminderServiceTest.cs:line 76
  InnerException: 

ИЗМЕНИТЬ 2

Я решил использовать явные ассоциации внешних ключей.

class ArticleMap : EntityTypeConfiguration<Article>
{
    public ArticleMap()
    {
        // Primary Key
        this.HasKey(t => t.ID);
        this.Property(t => t.ID)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        // Strongly typed FK properties
        this.Property(t => t.StageID).IsRequired();
        this.Property(t => t.ArticleTypeID).IsRequired();

        // Navigation Models
        this.HasRequired(t => t.Stage);
        this.HasRequired(t => t.ArticleType);

        // Table & Column Mappings
        this.ToTable("items");
        this.Property(t => t.ID).HasColumnName("item_id");
        this.Property(t => t.StageID).HasColumnName("stage_id");
        this.Property(t => t.ArticleTypeID).HasColumnName("article_type_id");
    }
}


protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new ArticleTypeMap());
    modelBuilder.Configurations.Add(new StageMap());
    modelBuilder.Configurations.Add(new ArticleMap());
}

Все еще не работает.

Используя новый подход сопоставления внешних ключей, я попытался переключить ключи article_type_id и stage_id.

this.Property(t => t.StageID).HasColumnName("article_type_id"); // <-- Switched
this.Property(t => t.ArticleTypeID).HasColumnName("stage_id");  // <-- Switched

Внезапно ошибка исчезла. В настоящее время сбит с толку прямо сейчас. Я думаю, что модели ArticleType почему-то не нравится внешний ключ «article_type_id».

ИЗМЕНИТЬ 3

После добавления .HasForeignKey(...) в сопоставления моей навигационной модели я получил новую ошибку: Неизвестный столбец "ArticleType_ID" в "списке полей"

class ArticleMap : EntityTypeConfiguration<Article>
{
    public ArticleMap()
    {
        // Primary Key
        this.HasKey(t => t.ID);
        this.Property(t => t.ID)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        // Foreign Key Properties
        this.Property(t => t.StageID)
            .IsRequired();
        this.Property(t => t.JournalID)
            .IsRequired();
        this.Property(t => t.ArticleTypeID)
            .IsRequired();

        // Navigational Models
        this.HasRequired(t => t.Stage); // This works
        this.HasRequired(t => t.ArticleType)
            .WithMany()
            .HasForeignKey(t => t.ArticleTypeID); // Newly added

        // Table & Column Mappings
        this.ToTable("items");
        this.Property(t => t.ID).HasColumnName("item_id");
        this.Property(t => t.ArticleTypeID).HasColumnName("article_type_id");
        this.Property(t => t.StageID).HasColumnName("stage_id");
    }
}

class ArticleTypeMap : EntityTypeConfiguration<ArticleType>
{
    public ArticleTypeMap()
    {
        // Primary Key
        this.HasKey(t => t.ID);

        // Properties
        this.Property(t => t.ID)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        this.Property(t => t.Title)
            .HasMaxLength(100)
            .IsRequired();

        // Table & Column Mappings
        this.ToTable("article_types");
        this.Property(t => t.ID).HasColumnName("article_type_id"); // <-- Apparently, this is no longer mapped.
        this.Property(t => t.Title).HasColumnName("title");
    }
}

person Yorro    schedule 14.09.2013    source источник
comment
Я советую вам явно добавить внешние ключи в ваш код. Поэтому добавьте свойство «ArticleTypeID» и «StageID» в класс «Article». Тем не менее, EntityFramework должен подобрать эти отношения без необходимости настройки с использованием Fluent API или иным образом.   -  person Dabblernl    schedule 14.09.2013
comment
@Dabblernl Спасибо. Но я пытался избежать этого решения, поэтому я разместил этот вопрос, но я попробую это как свое окончательное решение.   -  person Yorro    schedule 14.09.2013
comment
Почему вы пытаетесь избежать этого? Вам будет намного легче жить, если вы сделаете...   -  person Dabblernl    schedule 14.09.2013
comment
Вы можете опубликовать полную ошибку из отладчика? существует несколько выходов ошибок, которые могут подпадать под эту категорию ошибок.   -  person Claies    schedule 15.09.2013
comment
@Dabblernl - Изначально я стремился к более объектно-ориентированному подходу к своим ассоциациям. Но после дальнейшего изучения вопроса Внешние ключевые ассоциации и независимые ассоциации похоже, что я в конце концов откажусь от этой попытки. Более подробное объяснение: stackoverflow.com/a/12609414/1027250   -  person Yorro    schedule 16.09.2013
comment
@AndrewCounts - Как мне это сделать? Вы говорите о полной трассировке стека или о полном сообщении об ошибке? Смотрите мой отредактированный пост.   -  person Yorro    schedule 16.09.2013


Ответы (2)


При поиске конкретного сообщения об ошибке причиной этого является ошибка настройки отношения «один ко многим» как отношения «один к одному» с использованием:

modelBuilder.Entity<Article>
.HasRequired(t => t.ArticleType)
.WithOptional()
.HasForeignKey(...);

Пока должно быть:

modelBuilder.Entity<Article>
.HasRequired(t => t.ArticleType)
.WithMany()
.HasForeignKey(...);

Вы уже указали на это в своем собственном примере кода. Поскольку код, показанный вами для ArticleType и Stage, идентичен, не имеет смысла, что этот код является причиной проблемы. Где-то еще в вашем коде должно быть определено отношение один к одному между Article и ArticleType. Или каким-то образом у вас изначально было неправильное отношение, но исправленное определение Fluent не подхватывается Entity Framework.

person Dabblernl    schedule 16.09.2013
comment
Я решил явно объявить свойства внешнего ключа, ошибка все еще существует, поэтому проблема где-то возникает. Смотрите мой отредактированный пост. Спасибо! - person Yorro; 16.09.2013
comment
После добавления свойств внешнего ключа я добавил файл .HasForeignKey(...). Внезапно не удалось сопоставить article_type_id. Смотрите мой отредактированный пост. - person Yorro; 17.09.2013
comment
Хорошо, я только что узнал, что где-то еще есть однозначная связь между ArticleType и Recipient (какой-то другой класс, который даже не вызывается, но вызывает ошибку) - person Yorro; 17.09.2013

Вы можете взять файл .edmx из визуального stdio и сопоставить свою базу данных с этим файлом, чтобы автоматически создать сопоставление отношений объекта в соответствии со схемой базы данных.

person Samir    schedule 14.09.2013
comment
Это вообще не отвечает на вопрос, для одного он использует код-сначала - person Not loved; 14.09.2013