使用EF Code First的多对多关系

我有两个类定义如下:

public class Questionnaire { public int QuestionnaireID { get; set; } public string Title { get; set; } public bool Active { get; set; } public virtual ICollection Questions { get; set; } public virtual ICollection Vendors { get; set; } } public class Vendor { public int VendorID { get; set; } public string VendorName { get; set; } public virtual ICollection OpenQuestionnaires { get; set; } public virtual ICollection SubmittedQuestionnaires { get; set; } public virtual ICollection QuestionnaireUsers { get; set; } } 

我相信这是在这些类之间建立多对多关系的正确方法,并且在构建项目时,我希望创建三个表。

但是,当我尝试将一个调查问卷与两个不同的供应商联系起来时,在尝试保存更改时会收到以下错误(context.SaveChanges()):

*违反了多重约束。 ‘QuestionnaireApp.Models.Vendor_OpenQuestionnaires’关系的’Vendor_OpenQuestionnaires_Source’角色具有多重性1或0..1。*

如果我只将调查表分配给一个供应商,保存更改然后将其分配给另一个并再次保存更改我不再收到错误; 然而,问卷调查仅与其分配的最后一个供应商相关,表明(充其量)创建了一对多关系。

我希望我在声明这些类之间的多对多关系的方式有问题,或者我需要添加到上下文类中来“鼓励”关系,但也许很多这样的多对象关系不受支持,或者无法使用“Code First”创建?

感谢您的时间,

贾森

如果您没有任何Fluent API代码,则您期望的映射依赖于EF Code First约定。 您期望在这里启动的约定是AssociationInverseDiscoveryConvention 。 现在,如果您查看Intellisense(可能还有文档),它会说明这个约定:

当相关类型之间仅存在一对导航属性时 ,检测导航属性为彼此的反转的惯例。

现在,这就是问题: QuestionnaireVendor之间没有“一对”导航属性。 Vendor两个集合参考QuestionnaireQuestionnaire一个集合参考Vendor 。 结果是该约定未被应用,并且EF映射实际上是三个一对多关系,其中仅一个末端在模型中作为导航属性公开。

此外,您希望实现的映射不适用于您的模型:您无法将一端 Questionnaire.Vendors映射到两端 Vendor.OpenQuestionnairesVendor.SubmittedQuestionnaires

一种解决方法是通过以下方式更改模型:

 public class Vendor { public int VendorID { get; set; } public string VendorName { get; set; } [NotMapped] public IEnumerable OpenQuestionnaires { get { return Questionnaires.Where(q => q.IsActive); } } [NotMapped] public IEnumerable SubmittedQuestionnaires { get { return Questionnaires.Where(q => !q.IsActive); } } public virtual ICollection Questionnaires { get; set; } public virtual ICollection QuestionnaireUsers { get; set; } } 

现在Vendor.Questionnaires映射到Questionnaire.VendorsAssociationInverseDiscoveryConvention应检测到这一点),帮助属性OpenQuestionnairesSubmittedQuestionnaires允许您拉出所选项目。 (我不确定IsActive是否是你的区别标志。否则你必须引入一些新的旗帜。)

[NotMapped]属性就是为了使它明确。 它可能没有必要,因为EF无论如何都不会仅使用getter来映射IEnumerable集合和只读属性。

去看看,经过一个小时左右的搜索,我在发布问题30秒后找到确切的答案。

解决方案是将以下内容添加到上下文类中:

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

我通过阅读Stack Overflowpost找到了答案: EF Code First多对多无法正常工作