2016-12-23 33 views
5

我在使用繼承(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; } 

} 

而且的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"); 

    } 
} 

好吧,讓我們言歸正傳。正如你可以在父提案模型中看到的,我有屬性CreatorId - 對Employee實體的引用。員工內部模型我想要有兩個導航屬性加載創建的子類型提案,如下所示:

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

} 

但它會導致遷移錯誤。在應用遷移之後,我在提案表中提供了兩個對Employee實體(CreatorId,EmployeeUserId)的引用,而不是一個(CreatorId)。當我改變了導航性能:

public class Employee 
{  
    public ICollection<Proposal> CreatedProposals { get; set; } 
} 

模型是正確的(只有一個參考員工提案表內),但我還是不能包括()爲Employee模型CreatedProposalCustoms和CreatedProposalLeaves分開。

這個問題可能是我的DbContext的配置裏面,但我不知道如何正確設置它:/

+1

加入'public DbSet ProposalLeaves {get;組; }'和'public DbSet ProposalCustoms {get;組; }'到你的'AppDbContext'類。然後你可以在'Employee'中創建你的導航屬性。並讓他們成爲'虛擬'。 – Kos

+0

同意添加,但我不會讓它們變成虛擬的,除非您實際上針對延遲加載。 – Zephire

+0

@Kos我應用了您的更改,但仍然無效。 '.include(e => e.CreatedLeaves)'總是爲空列表,而'_context.ProposalLeave.Where(pl => pl.CreatorId == emp.UserId).ToList();'''_context.Proposal.OfType ()。其中​​(pl => pl.CreatorId == emp.UserId).ToList()'工作正常:/哦,我在Proposal表中仍然有不必要的EmployeeUserId。 – Kuba

回答

3

的問題是,當你有導航性能,EF核心也將創造兩個外鍵,你已經發現了。

一種解決方法可能是擁有non-mapped navigation properties,它只是用基類包裝您的集合的投射。

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>(); 
} 

當兩個非映射屬性將只是作爲簡寫Proposals.OfType<T>()

或者,如果你想讓它更通用:

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

然後用它作爲employee.AllProposals<ProposalLeave>().Where(p => p.LeaveStart >= DateTime.Now).ToListAsync()

+0

謝謝。它根本沒有解決我的問題,但這確實是有幫助的提示;) – Kuba