子实体的继承和导航属性

Kub*_*uba 6 c# ef-database-first entity-framework-core asp.net-core

我在使用继承(TPH - 目前在 EF Core 中唯一可用)时遇到导航属性问题。

我的层次结构模型:

public class Proposal
{
    [Key]
    public int ProposalId { get; set; }

    [Required, Column(TypeName = "text")]
    public string Substantiation { get; set; }

    [Required]
    public int CreatorId { get; set; }

    [ForeignKey("CreatorId")]
    public Employee Creator { get; set; }

}

public class ProposalLeave : Proposal
{
    [Required]
    public DateTime LeaveStart { get; set; }

    [Required]
    public DateTime LeaveEnd { get; set; }
}

public class ProposalCustom : Proposal
{
    [Required, StringLength(255)]
    public string Name { get; set; }

}
Run Code Online (Sandbox Code Playgroud)

和 DbContext 的一部分:

public class AppDbContext : IdentityDbContext<User, Role, int>
{

    public DbSet<Employee> Employee { get; set; }
    public DbSet<Proposal> Proposal { get; set; }

    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Proposal>()
            .HasDiscriminator<string>("proposal_type")
            .HasValue<Proposal>("proposal_base")
            .HasValue<ProposalCustom>("proposal_custom")
            .HasValue<ProposalLeave>("proposal_leave");

    }
}
Run Code Online (Sandbox Code Playgroud)

好的,让我们进入正题。正如您在父 Proposal 模型中看到的,我有属性 CreatorId - 对 Employee 实体的引用。在 Employee 模型中,我希望有两个导航属性来加载创建的子类型提案,如下所示:

public class Employee
{
    public ICollection<ProposalCustom> CreatedProposalCustoms { get; set; } 
    public ICollection<ProposalLeave> CreatedProposalLeaves { get; set; } 

}
Run Code Online (Sandbox Code Playgroud)

但它会导致迁移错误。在我应用迁移后,我在 Proposal 表中有两个对 Employee 实体(CreatorId、EmployeeUserId)的引用,而不是一个(CreatorId)。当我将导航属性更改为:

public class Employee
{      
    public ICollection<Proposal> CreatedProposals { get; set; } 
}
Run Code Online (Sandbox Code Playgroud)

模型是正确的(Proposal 表中只有一个对 Employee 的引用),但我仍然无法分别 Include() 到 Employee 模型 CreatedProposalCustoms 和 CreatedProposalLeaves。

问题可能出在我的 DbContext 配置中,但我不知道如何正确设置它:/

Tse*_*eng 5

问题是,当您必须导航属性时,EF Core 还会创建两个外键,正如您已经发现的那样。

一种解决方法可能是使用非映射导航属性,它只是用基类包装您的集合的转换。

public class Employee
{
    public IDbSet<Proposal> Proposals { get; set; } 
    [NotMapped]
    public IQueryable<ProposalCustom> CreatedProposalCustoms { get; } => Proposals.OfType<ProposalCustom>();
    [NotMapped]
    public IQueryable<ProposalLeave> CreatedProposalLeaves { get; } => Proposals.OfType<ProposalLeave>();
}
Run Code Online (Sandbox Code Playgroud)

两个非映射属性只是作为简写 Proposals.OfType<T>()

或者,如果您希望它更通用:

public class Employee
{
    public IDbSet<Proposal> Proposals { get; set; } 
    public IQueryable<T> AllProposals<T>() where T :Proposal => Proposals.OfType<T>();
}
Run Code Online (Sandbox Code Playgroud)

然后将其用作employee.AllProposals<ProposalLeave>().Where(p => p.LeaveStart >= DateTime.Now).ToListAsync().

  • 谢谢。它根本没有解决我的问题,但它确实很有帮助的提示;) (2认同)