两个实体之间的代码优先外键
本文关键字:代码 之间 两个 实体 | 更新日期: 2023-09-27 18:02:12
好的,我在这里错过了什么,或者这只是能够用数据注释完成?
我有一个文档实体模型,它有一个添加文档(一对一关系)的用户的外键:
[Table("Documents", Schema = "Configuration")]
public class Document : IPrimaryKey {
[Key]
public long Id { get; set; }
[Required]
public string OrginalName { get; set; }
[Required]
public DocumentTypes DocumentType { get; set; }
[Required]
public MIMETypes MIMEType { get; set; }
[Required]
public byte[] Data { get; set; }
[DefaultValue(false)]
public bool IsPublic { get; set; }
[Required]
public DateTimeOffset DateTimeAdded { get; set; }
[Required]
public long AddedByUser { get; set; }
[ForeignKey("AddedByUser")]
public virtual Details Details { get; set; }
}
然后我有一个User (Details)实体,它可以有一个图像文件(存储在文档实体模型中(无|一对一关系):
[Table("Details", Schema = "User")]
public class Details : IPrimaryKey {
[Key]
public long Id { get; set; }
[Required]
public string UserId { get; set; }
[ForeignKey("UserId")]
public AppUser User { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<Address> Addresses { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<Email> Emails { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<PhoneNumber> PhoneNumbers { get; set; }
public ICollection<NotificationHistory> NotificationHistory { get; set; }
public long TimeZoneId { get; set; }
public long? ImageId { get; set; }
[ForeignKey("ImageId")]
public virtual Document Document { get; set; }
[ForeignKey("TimeZoneId")]
public virtual TimeZone TimeZone { get; set; }
}
当我尝试创建迁移时,我得到这个错误:
无法确定对象之间关联的主要端类型"StACS.PeoplesVoice.DataAccessLayer.EntityModels.User.Details"answers"StACS.PeoplesVoice.DataAccessLayer.EntityModels.Configuration.Document"。必须显式配置此关联的主体端使用关系流畅API或数据注释。
更新:
当我还在研究这个问题时,我做了两个更改,并能够解决这个错误,但这在我的数据库中创建了一个意想不到的结果。
在文档实体中我添加了:
public virtual ICollection<Details> Details { get; set; }
在Details (user) Entity I中添加:
puflic virtual ICollection<Document> Documents { get; set; }
在我的DB表中,我现在在我想要的字段上有外键,但我分别为每个字段都有一个辅助外键。
我试图删除单个虚拟引用,只留下iccollection虚拟引用,现在我没有外键了。
更新(基于Akash Kava建议):
我做了以下更改[表("文档",模式="配置")]public类Document: IPrimaryKey {(需要)公共字符串原始名称{获取;设置;}
[Required]
public DocumentTypes DocumentType { get; set; }
[Required]
public MIMETypes MIMEType { get; set; }
[Required]
public byte[] DocumentData { get; set; }
[DefaultValue(false)]
public bool IsPublic { get; set; }
[Required]
public DateTimeOffset DateTimeAdded { get; set; }
[Required]
public long AddedByUser { get; set; }
[Key]
public long Id { get; set; }
[ForeignKey("AddedByUser")]
[InverseProperty("Image")]
public virtual Details User { get; set; }
}
[Table("Details", Schema = "User")]
public class Details : IPrimaryKey {
[Required]
public string UserId { get; set; }
[ForeignKey("UserId")]
public AppUser User { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<Address> Addresses { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<Email> Emails { get; set; }
[CollectionRequired(MinimumCollectionCount = 1)]
public ICollection<PhoneNumber> PhoneNumbers { get; set; }
public ICollection<NotificationHistory> NotificationHistory { get; set; }
public long TimeZoneId { get; set; }
public long? ImageId { get; set; }
[ForeignKey("ImageId")]
[InverseProperty("User")]
public Document Image { get; set; }
[ForeignKey("TimeZoneId")]
public virtual TimeZone TimeZone { get; set; }
[Key]
public long Id { get; set; }
}
我已经注释掉了Fluent API代码
无法确定对象之间关联的主要端类型"StACS.PeoplesVoice.DataAccessLayer.EntityModels.User.Details"answers"StACS.PeoplesVoice.DataAccessLayer.EntityModels.Configuration.Document"。必须显式配置此关联的主体端使用关系流畅API或数据注释。
您也可以使用数据注释实现相同的目标,您缺少InverseProperty
属性,它在这种情况下解决了歧义。从概念上讲,每个导航属性都有逆导航属性,EF根据类型自动检测并假设逆属性,但如果两个实体通过多个FK属性相互关联,则必须在相应的导航属性上显式指定InverseProperty属性。
我建议将InverseProperty放在每个导航属性上,这有助于减少EF的启动时间,因为EF不需要确定和验证模型。
,
public class AccountEmail {
public long AccountID {get;set;}
// Inverse property inside Account class
// which corresponds to other end of this
// relation
[InverseProperty("AccountEmails")]
[ForeignKey("AccountID")]
public Account Account {get;set;}
}
public class Account{
// Inverse property inside AccountEmail class
// which corresponds to other end of this
// relation
[InverseProperty("Account")]
public ICollection<AccountEmail> AccountEmails {get;set;}
}
我写了一个文本模板,根据当前模式生成所有这些导航属性。从https://github.com/neurospeech/atoms-mvc.net/tree/master/db-context-tt下载这三个文件,您可能需要定制它,因为它根据我们的框架添加了一些更多的东西,但它确实直接从数据库生成纯代码模型。
好了,我终于想通了。遗憾的是,这不是很直接,因为我认为数据注释应该工作,但它没有。
你必须使用Fluent API:
modelBuilder.Entity<Details>()
.HasOptional(x => x.Document)
.WithMany()
.HasForeignKey(x => x.ImageId);
modelBuilder.Entity<Document>()
.HasRequired(x => x.User)
.WithMany()
.HasForeignKey(x => x.AddedByUser);