我有两个定义的类:
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()):
*违反了多重约束。 'QuestionnaireApp.Models.Vendor_OpenQuestionnaires'关系的'Vendor_OpenQuestionnaires_Source'角色具有多重性1或0..1。*
如果我只将调查表分配给一个供应商,保存更改然后将其分配给另一个并再次保存更改我不再收到错误;然而,问卷调查仅与其分配的最后一个供应商相关,表明(充其量)创建了一对多关系。
我希望我在声明这些类之间的多对多关系的方式有问题,或者我需要在上下文类中添加一些内容以“鼓励”关系,但是,这样的多对多关系可能不受支持,或者无法使用“Code First”创建?
感谢您的时间,
杰森
答案 0 :(得分:2)
如果您没有任何Fluent API代码,则您预期的映射依赖于EF Code First约定。您希望在此处启用的约定是AssociationInverseDiscoveryConvention
。现在,如果您查看Intellisense(可能还有文档),它会说明这个约定:
检测导航属性的惯例是每个的反转 其他当两者之间只存在一对导航属性时 相关类型。
现在,问题是:Questionnaire
和Vendor
之间没有“一对”导航属性。您在Vendor
引用了Questionnaire
的两个集合,Questionnaire
中的一个集合引用了Vendor
。结果是这个约定没有得到应用,EF映射实际上三个一对多关系,只有一个端在模型中公开为导航属性。
此外,您的模型无法实现您想要实现的映射:您无法将一端 Questionnaire.Vendors
映射到两端 {{1} }和Vendor.OpenQuestionnaires
。
一种解决方法是按以下方式更改模型:
Vendor.SubmittedQuestionnaires
现在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
属性就是为了让它显而易见。这可能没有必要,因为EF不会仅使用getter映射[NotMapped]
集合和只读属性。
答案 1 :(得分:1)
去看看,经过一个小时左右的搜索,我会在发布问题30秒后找到确切答案。
解决方案是将以下内容添加到上下文类中:
modelBuilder.Entity<Vendor>()
.HasMany<Questionnaire>(x => x.OpenQuestionnaires)
.WithMany(x => x.Vendors)
.Map(x =>
{
x.MapLeftKey("vID");
x.MapRightKey("qID");
x.ToTable("VendorQuestionnaires");
});
我通过阅读Stack Overflow帖子找到了答案:EF Code First Many-to-Many not working