两个实体之间的代码优先外键

本文关键字:代码 之间 两个 实体 | 更新日期: 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);