私はInheritance(TPH - EF Coreの現時点でのみ利用可能です)を使用しているときにNavigation Propertiesに問題があります。
私の階層モデル:
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");
}
}
[OK]をポイントにしましょう。親プロポーザルモデルの内部で見ることができるように、私はCreatorIdというプロパティを持ちます - Employeeエンティティへの参照。 Employeeモデルの中で私は、以下のように、作成された子タイプの提案をロードするためのナビゲーションプロパティを2つ持っています:
public class Employee
{
public ICollection<ProposalCustom> CreatedProposalCustoms { get; set; }
public ICollection<ProposalLeave> CreatedProposalLeaves { get; set; }
}
しかし、それは移行エラーを引き起こす。私がマイグレーションを適用した後、プロポーザルテーブルの中にEmployeeエンティティ(CreatorId、EmployeeUserId)の参照がCreatorIdの代わりに2つあります。ナビゲーションプロパティを次のように変更したとき:
public class Employee
{
public ICollection<Proposal> CreatedProposals { get; set; }
}
モデルは正しかった(プロポーザル表の中のEmployeeへの参照は1つしかなかった)が、従業員モデルCreatedProposalCustomsとCreatedProposalLeavesを別々にInclude()することはできない。
問題はおそらく私のDbContext設定の中にありますが、正しく設定する方法はわかりません:/
問題は、プロパティをナビゲーションする必要がある場合、EF Coreは既に見つけたように2つの外部キーも作成することです。
1つの回避策は、 マップされていないナビゲーションプロパティを持つことです 。これは、コレクションのキャストを基本クラスでラップするだけです。
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>();
}
2つのマップされていないプロパティが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()
として使用しますemployee.AllProposals<ProposalLeave>().Where(p => p.LeaveStart >= DateTime.Now).ToListAsync()
。