Отношения многие ко многим с использованием EF Code First - PullRequest
2 голосов
/ 27 июля 2011

У меня есть два класса, определенных как таковые:

public class Questionnaire
    {
        public int QuestionnaireID { get; set; }
        public string Title { get; set; }
        public bool Active { get; set; }
        public virtual ICollection<Question> Questions { get; set; }
        public virtual ICollection<Vendor> Vendors { get; set; }
    }

public class Vendor
    {
        public int VendorID { get; set; }

        public string VendorName { get; set; }

        public virtual ICollection<Questionnaire> OpenQuestionnaires { get; set; }

        public virtual ICollection<Questionnaire> SubmittedQuestionnaires { get; set; }

        public virtual ICollection<QuestionnaireUser> QuestionnaireUsers { get; set; }
    }

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

Однако, когда я пытаюсь связать одну анкету с двумя разными поставщиками, я получаю следующую ошибку при попытке сохранить изменения (context.SaveChanges ()):

* Нарушено ограничение множественности. Роль 'Vendor_OpenQuestionnaires_Source' отношения 'QuestionnaireApp.Models.Vendor_OpenQuestionnaires' имеет кратность 1 или 0..1. *

Если я назначу Вопросник только одному Продавцу, сохраню изменения, а затем назначу его другому и снова сохраню изменения, я больше не получаю ошибку; однако вопросник тогда относится только к последнему поставщику, которому он был назначен, указывая, что (в лучшем случае) создается отношение один ко многим.

Я надеюсь, что что-то не так с тем, как я объявляю отношения «многие ко многим» между этими классами, или, возможно, мне нужно что-то добавить к контекстному классу, чтобы «поощрить» отношения, но, возможно, такие отношения «многие ко многим» не поддерживаются или не могут быть созданы с помощью «Code First»?

Спасибо за ваше время,

Jason

Ответы [ 2 ]

2 голосов
/ 28 июля 2011

Если у вас нет кода Fluent API, ожидаемое сопоставление зависит от соглашений EF Code First.Соглашение, которое вы ожидаете здесь заключить, это AssociationInverseDiscoveryConvention.Теперь, если вы посмотрите в Intellisense (и, вероятно, также в документации), он говорит об этом соглашении:

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

Теперь вот в чем проблема: у вас нет только «одной пары» навигационных свойств между Questionnaire и Vendor.У вас есть две коллекции в Vendor, ссылающиеся на Questionnaire, и одна коллекция в Questionnaire, ссылающиеся на Vendor.В результате это соглашение не применяется, и EF отображает на самом деле три взаимосвязи один-ко-многим только с одним концом, отображаемым в качестве свойства навигации в модели.

Кроме того, вы отображаетежелать достичь невозможно с вашей моделью: вы не можете отобразить один конец Questionnaire.Vendors на два конца Vendor.OpenQuestionnaires и Vendor.SubmittedQuestionnaires.

OneОбходной путь - изменить модель следующим образом:

public class Vendor
{
    public int VendorID { get; set; }

    public string VendorName { get; set; }

    [NotMapped]
    public IEnumerable<Questionnaire> OpenQuestionnaires
    {
        get { return Questionnaires.Where(q => q.IsActive); }
    }

    [NotMapped]
    public IEnumerable<Questionnaire> SubmittedQuestionnaires
    {
        get { return Questionnaires.Where(q => !q.IsActive); }
    }

    public virtual ICollection<Questionnaire> Questionnaires { get; set; }
    public virtual ICollection<QuestionnaireUser> QuestionnaireUsers { get; set; }
}

Теперь Vendor.Questionnaires сопоставлен с Questionnaire.Vendors (AssociationInverseDiscoveryConvention должен это определить), а вспомогательные свойства OpenQuestionnaires и SubmittedQuestionnaires позволяют вамвытащить выбранные предметы.(Я не уверен, является ли IsActive вашим отличительным флагом. В противном случае вам нужно ввести какой-то новый флаг.)

Атрибут [NotMapped] здесь только для того, чтобы сделать его явным.Вероятно, в этом нет необходимости, потому что EF не будет отображать коллекции IEnumerable и свойства только для чтения в любом случае только с геттером.

1 голос
/ 28 июля 2011

Пойди к цифре, примерно через час поиска я пойду и найду точный ответ через 30 секунд после того, как отправлю свой вопрос.

Решением было добавить следующее в класс контекста:

modelBuilder.Entity<Vendor>()
                .HasMany<Questionnaire>(x => x.OpenQuestionnaires)
                .WithMany(x => x.Vendors)
                .Map(x =>
                    {
                        x.MapLeftKey("vID");
                        x.MapRightKey("qID");
                        x.ToTable("VendorQuestionnaires");
                    });

Я нашел ответ, прочитав это сообщение о переполнении стека: EF Code First Many-to-Many не работает

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...