Many-to-many relationships using EF Code First

妖精的绣舞 提交于 2019-12-06 11:33:24

If you don't have any Fluent API code your expected mapping relies on EF Code First conventions. The convention which you expect to kick in here is the AssociationInverseDiscoveryConvention. Now if you look in Intellisense (and probably also documentation) it says about this convention:

Convention to detect navigation properties to be inverses of each other when only one pair of navigation properties exists between the related types.

Now, that's the problem: You don't have only "one pair" of navigation properties between Questionnaire and Vendor. You have two collections in Vendor refering to Questionnaire and one collection in Questionnaire refering to Vendor. The result is that this convention doesn't get applied and EF maps actually three one-to-many relationships with only one end exposed as navigation property in the model.

Moreover the mapping you want to achieve is not possible with your model: You cannot map the one end Questionnaire.Vendors to the two ends Vendor.OpenQuestionnaires and Vendor.SubmittedQuestionnaires.

One workaround is to change your model the following way:

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; }
}

Now Vendor.Questionnaires is mapped to Questionnaire.Vendors (AssociationInverseDiscoveryConvention should detect this) and the helper properties OpenQuestionnaires and SubmittedQuestionnaires allow you to pull out the selected items. (I'm not sure if IsActive is your distinguishing flag. Otherwise you have to introduce some new flag.)

The [NotMapped] attribute is just here to make it explicite. It is probably not necessary because EF won't map IEnumerable collections and readonly properties with only a getter anyway.

jasongullickson

Go figure, after an hour or so of searching, I go and find the exact answer 30 seconds after I post my question.

The solution was to add the following to the context class:

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

I found the answer by reading this Stack Overflow post: EF Code First Many-to-Many not working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!