C# 包括原因InvalidCastException
我对Entity Framework Core 1.1中的此查询有问题:C# 包括原因InvalidCastException,c#,asp.net-core,entity-framework-core,C#,Asp.net Core,Entity Framework Core,我对Entity Framework Core 1.1中的此查询有问题: var leaves = _context.Proposal.OfType<ProposalLeave>() .Include(l => l.Creator).ThenInclude(e => e.User) .Include(l=>l.LeaveType) // this include causes the exception
var leaves = _context.Proposal.OfType<ProposalLeave>()
.Include(l => l.Creator).ThenInclude(e => e.User)
.Include(l=>l.LeaveType) // this include causes the exception
.Include(l => l.ProposalLeaveStatuses).ThenInclude(l => l.ProposalLeaveStatus)
.ToList();
在我查询之前,它甚至可以与.Include(l=>l.LeaveType)
一起使用,没有任何例外
我在EF github上发现了一些关于InvalidCastException的bug问题,但在EF Core1.1中,所有这些问题都被标记为已修复
@更新
在这里,您可以下载重现该问题的VS2015项目:
.
设置:
不幸的是,我所能做的就是确认一个明显的事实,即问题是由EF核心缺陷引起的 我能够将复制减少到以下内容: 型号: 查询:
var proposalCustoms=db.Proposal.OfType()
.包括(l=>l.ProposalType)
.ToList();
var proposalLeaves=db.Proposal.OfType()
.包括(l=>l.LeaveType)
.ToList();
尽管ProposalCustom
和ProposalLeave
看起来很相似,但第一个查询始终有效,第二个则无效(如下文所示,在某些情况下有效)
为什么我肯定这是一个错误。首先,因为查询和/或模型/配置没有问题。看起来这是由几个因素的组合造成的,首先是TPH、派生类属性的数量和类型,以及派生实体的类名(字母顺序?)
例如,如果没有LeaveEnd
属性,则第二个查询可以工作。最有趣的部分(当然取决于视图)是,如果您将ProposalCustom
类重命名为ProposalXCustom
,或ProposalLeave
重命名为ProposalLeave
,换句话说,将有问题的实体类名称按字母顺序排在第一位(我知道这听起来很疯狂),在没有任何数据库结构/映射更改的情况下,查询工作正常
我建议您将其报告给EF核心存储库<代码>证实列和
必需
/列
属性似乎不会影响行为。另外,请注意,第一个查询总是有效的,执行顺序并不重要 没有完整的模型就无法复制。如果您注释掉.Include(l=>l.ProposalLeaveStatus)。然后注释掉Include(l=>l.ProposalLeaveStatus)
行,会发生什么情况?@IvanStoev它仍然不起作用。只有删除行:Include(l=>l.LeaveType)
才能解决我的问题。这就是我在问题中跳过ProposalLeaveStatus和ProposalLeaveStatus模型定义的原因。稍后,我将通过添加DbContextI的重要部分来更新我的问题。但这似乎会对过程产生某种影响,因为w/o。然后include(e=>e.User)
和第一条评论中提到的行它不会发生,我的意思是,它在没有错误的情况下工作。@IvanStoev我添加了VS 2015项目,重现了我的问题。你能确认你有相同的错误,它可能是EF核心的问题吗?问题报告。谢谢你的帮助。
public class Proposal
{
[Key]
public int ProposalId { get; set; }
[Required]
public DateTime DateCreated { 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; }
[Required]
public int ProposalLeaveTypeId { get; set; }
[ForeignKey("ProposalLeaveTypeId")]
public virtual ProposalLeaveType LeaveType { get; set; }
public virtual ICollection<ProposalLeaveStatuses> ProposalLeaveStatuses { get; set; }
}
public class ProposalLeaveType
{
[Key]
public int LeaveTypeId { get; set; }
[Required, StringLength(255)]
public string Name { get; set; }
[Required, Column(TypeName = "text")]
public string Description { get; set; }
public ICollection<ProposalLeave> ProposalLeaves { get; set; }
}
public class AppDbContext : IdentityDbContext<User, Role, int>
{
public DbSet<Proposal> Proposal { get; set; }
public DbSet<ProposalLeaveStatus> ProposalLeaveStatus { get; set; }
public DbSet<ProposalLeaveStatuses> ProposalLeaveStatuses { get; set; }
public DbSet<ProposalLeaveType> ProposalLeaveType { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// proposal hierarchy
modelBuilder.Entity<Proposal>()
.HasDiscriminator<string>("proposal_type")
.HasValue<Proposal>("proposal_base")
.HasValue<ProposalCustom>("proposal_custom")
.HasValue<ProposalLeave>("proposal_leave");
// proposal statuses many to many
modelBuilder.Entity<ProposalLeaveStatuses>()
.HasOne(pt => pt.Proposal)
.WithMany(p => p.ProposalLeaveStatuses)
.HasForeignKey(pt => pt.ProposalId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<ProposalLeaveStatuses>()
.HasOne(pt => pt.ProposalLeaveStatus)
.WithMany(t => t.ProposalLeaveStatuses)
.HasForeignKey(pt => pt.ProposalLeaveStatusId);
//Substantially, there are nothing about Proposal Leave Types, cause its relation one-to-many modeled using data annotations.
}
}
var leaveTypes = _context.ProposalLeaveType.Include(plt => plt.ProposalLeaves).ToList();
public class Proposal
{
[Key]
public int ProposalId { get; set; }
[Required, Column(TypeName = "text")]
public string Substantiation { get; set; }
public DateTime DateCreated { get; set; }
}
public class ProposalCustom : Proposal
{
[Required, StringLength(255)]
public string Name { get; set; }
public int ProposalTypeId { get; set; }
[ForeignKey("ProposalTypeId")]
public virtual ProposalCustomType ProposalType { get; set; }
}
public class ProposalCustomType
{
[Key]
public int ProposalTypeId { get; set; }
[Required, StringLength(255)]
public string Name { get; set; }
[Required, Column(TypeName = "text")]
public string Description { get; set; }
public ICollection<ProposalCustom> ProposalCustoms { get; set; }
}
public class ProposalLeave : Proposal
{
public DateTime LeaveStart { get; set; }
public DateTime LeaveEnd { get; set; }
public int ProposalLeaveTypeId { get; set; }
[ForeignKey("ProposalLeaveTypeId")]
public virtual ProposalLeaveType LeaveType { get; set; }
}
public class ProposalLeaveType
{
[Key]
public int LeaveTypeId { get; set; }
[Required, StringLength(255)]
public string Name { get; set; }
[Required, Column(TypeName = "text")]
public string Description { get; set; }
public ICollection<ProposalLeave> ProposalLeaves { get; set; }
}
public DbSet<Proposal> Proposal { get; set; }
public DbSet<ProposalCustomType> ProposalCustomType { get; set; }
public DbSet<ProposalLeaveType> ProposalLeaveType { get; set; }
modelBuilder.Entity<Proposal>()
.HasDiscriminator<string>("proposal_type")
.HasValue<Proposal>("proposal_base")
.HasValue<ProposalCustom>("proposal_custom")
.HasValue<ProposalLeave>("proposal_leave");
db.Proposal.Add(new ProposalLeave
{
Substantiation = "S1",
DateCreated = DateTime.Today,
LeaveStart = DateTime.Today,
LeaveEnd = DateTime.Today,
LeaveType = new ProposalLeaveType { Name = "PLT1", Description = "PLT1" }
});
db.Proposal.Add(new ProposalCustom
{
Substantiation = "S2",
Name = "PC1",
ProposalType = new ProposalCustomType { Name = "PCT1", Description = "PCT1" }
});
db.SaveChanges();
var proposalCustoms = db.Proposal.OfType<ProposalCustom>()
.Include(l => l.ProposalType)
.ToList();
var proposalLeaves = db.Proposal.OfType<ProposalLeave>()
.Include(l => l.LeaveType)
.ToList();