C# 实体框架包括每个层次结构表的派生类型上的关系

C# 实体框架包括每个层次结构表的派生类型上的关系,c#,entity-framework,C#,Entity Framework,如果集合类型是每个层次结构设计的表,并且关系是在禁用延迟加载的派生类型上定义的,我如何在集合中包含属性的关系 我试图避免的是在基类型上声明关系,或者使用多个DB调用来检索关系。有办法解决这个问题吗 尝试和错误 我已尝试使用类型为的,但收到此消息 System.ArgumentException-包含路径表达式必须引用在类型上定义的导航属性。使用虚线路径作为参考导航属性,选择运算符作为集合导航属性 我已尝试将用作,但收到此错误 System.InvalidOperationException-指定

如果集合类型是每个层次结构设计的表,并且关系是在禁用延迟加载的派生类型上定义的,我如何在集合中包含属性的关系

我试图避免的是在基类型上声明关系,或者使用多个DB调用来检索关系。有办法解决这个问题吗

尝试和错误 我已尝试使用类型为的
,但收到此消息

System.ArgumentException-包含路径表达式必须引用在类型上定义的导航属性。使用虚线路径作为参考导航属性,选择运算符作为集合导航属性

我已尝试将
用作
,但收到此错误

System.InvalidOperationException-指定的包含路径无效。EntityType“Sandbox.TPHMcve.Person”未声明名为“Buildings”的导航属性

例子 请不要把重点放在这个愚蠢的例子的业务细节上,这是一个mcve来说明我收到的错误。我的实际项目与学校/学校系统等无关

结构
  • 大学里的学校有人
  • 一个人不是学生就是老师
  • 学生有零本或多本借阅的教材
  • 教师可被指定为一栋或多栋校园建筑的看管人/监护人
代码 SchoolService.cs

public sealed class School
{
    public int SchoolId { get; set; }
    public string Name { get; set; }
    public List<Person> EntitiesOfSchool { get; set; }
}

public abstract class Person
{
    public int PersonId { get; set; }
    public string Name { get; set; }
    public School PrimarySchool { get; set; }
    public int SchoolId { get; set; }
}

public sealed class Teacher : Person
{
    public ICollection<Building> Buildings { get; set; }
}

public sealed class Student : Person
{
    public ICollection<CourseBook> BooksOnLoan { get; set; }
}

public sealed class Building
{
    public int BuildingId { get; set; }
    public string Name { get; set; }
    public Teacher AssignedGuardian { get; set; }
    public int GuardianId { get; set; }
}

public sealed class CourseBook
{
    public int CourseBookId { get; set; }
    public int BookNumber { get; set; }
    public Student AssignedTo { get; set; }
    public int? AssignedToId { get; set; }
}
public sealed class UniversityDbContext : DbContext
{
    public UniversityDbContext() : base("Name=default")
    {
        this.Configuration.LazyLoadingEnabled = false; // disable lazy loading
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new SchoolMap());
        modelBuilder.Configurations.Add(new PersonMap());
        modelBuilder.Configurations.Add(new TeacherMap());
        modelBuilder.Configurations.Add(new StudentMap());
    }

    public DbSet<School> Schools { get; set; }
}
这是产生异常的实际代码


这是EF限制,即使在最新的EF核心中也无法解决。因此,没有办法在
IQueryable
Include
)级别解决这个问题。唯一已知的解决方案是物化和显式加载。感谢@IvanStoev的关注。太糟糕了,那太好了。你知道是否已经有一个功能请求,我可以把我的名字钉在上面吗?如果没有,我将创建一个。对于EF Core,我认为它是由链接下的评论跟踪的,并计划在v2.1.0中使用,看起来EF6没有计划进行这样的增强:-(再次感谢@IvanStoev。我已经创建了一个链接,并将一个参考链接添加回您在上面为EF Core发布的链接。我不会屏住呼吸,因为我知道EF6确实处于维护模式,主要针对EF Core的新功能。这是EF限制,即使在最新的EF Core中也没有解决。因此,没有办法解决这个问题在
IQueryable
Include
)解决此问题级别。唯一已知的解决方案是物化和显式加载。感谢@IvanStoev的关注。太糟糕了,那会很好。你知道我是否已经有一个功能请求可以将我的名字添加到其中?如果没有,我将创建一个。对于EF Core,我想它是由链接下的评论跟踪的,并计划在v2.1.0中发布,看起来EF6没有这样的增强计划:-(再次感谢@IvanStoev。我已经创建了一个链接,并添加了一个参考链接回您在上面为EF Core发布的链接。我不会屏住呼吸,因为我知道EF6确实处于维护模式,新功能主要针对EF Core。
public sealed class SchoolMap : EntityTypeConfiguration<School>
{
    public SchoolMap()
    {
        ToTable("Schools");
        HasKey(x => x.SchoolId);
        Property(x => x.SchoolId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Name).IsRequired().IsUnicode(true).HasMaxLength(200);
        HasMany(x => x.EntitiesOfSchool).WithRequired(x => x.PrimarySchool).HasForeignKey(person => person.SchoolId);
    }
}

public sealed class PersonMap : EntityTypeConfiguration<Person>
{
    public PersonMap()
    {
        ToTable("Persons");
        HasKey(x => x.PersonId);
        Property(x => x.PersonId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Name).IsRequired().IsUnicode(true).HasMaxLength(256);
        Map<Teacher>(configuration => configuration.Requires("PersonType").HasValue(1));
        Map<Student>(configuration => configuration.Requires("PersonType").HasValue(2));
    }
}

public sealed class TeacherMap : EntityTypeConfiguration<Teacher>
{
    public TeacherMap()
    {
        HasMany(x => x.Buildings).WithRequired(x => x.AssignedGuardian).HasForeignKey(x => x.GuardianId);
    }
}
public sealed class StudentMap : EntityTypeConfiguration<Student>
{
    public StudentMap()
    {
        HasMany(x => x.BooksOnLoan).WithOptional(x => x.AssignedTo).HasForeignKey(x => x.AssignedToId);
    }
}
public sealed class UniversityDbContext : DbContext
{
    public UniversityDbContext() : base("Name=default")
    {
        this.Configuration.LazyLoadingEnabled = false; // disable lazy loading
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new SchoolMap());
        modelBuilder.Configurations.Add(new PersonMap());
        modelBuilder.Configurations.Add(new TeacherMap());
        modelBuilder.Configurations.Add(new StudentMap());
    }

    public DbSet<School> Schools { get; set; }
}
CREATE TABLE [dbo].[Schools](
    [SchoolId] [int] IDENTITY(1,1) NOT NULL,
    [Name] Nvarchar (200) not null
CONSTRAINT [PK_Schools] PRIMARY KEY CLUSTERED 
(
    [SchoolId] ASC
)) ON [PRIMARY]
GO


CREATE TABLE [dbo].[Persons](
    [PersonId] [int] IDENTITY(1,1) NOT NULL,
    [SchoolId] [int] not null,
    [PersonType] [int] not null,
    [Name] nvarchar(256) not null
CONSTRAINT [PK_Persons] PRIMARY KEY CLUSTERED 
(
    [PersonId] ASC
)) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Buildings](
    [BuildingId] [int] IDENTITY(1,1) NOT NULL,
    [Name] nvarchar(200) not null,
    [GuardianId] [int] not null,
CONSTRAINT [PK_Buildings] PRIMARY KEY CLUSTERED 
(
    [BuildingId] ASC
)) ON [PRIMARY]
GO

CREATE TABLE [dbo].[CourseBooks](
    [CourseBookId] [int] IDENTITY(1,1) NOT NULL,
    [BookNumber] varchar(200) not null,
    [AssignedToId] [int] null,
CONSTRAINT [PK_CourseBooks] PRIMARY KEY CLUSTERED 
(
    [CourseBookId] ASC
)) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Persons] WITH CHECK ADD CONSTRAINT [FK_Schools_Persons] FOREIGN KEY([SchoolId])
REFERENCES [dbo].[Schools] ([SchoolId])

ALTER TABLE [dbo].[Buildings] WITH CHECK ADD CONSTRAINT [FK_Persons_Buildings] FOREIGN KEY([GuardianId])
REFERENCES [dbo].[Persons] ([PersonId])

ALTER TABLE [dbo].[CourseBooks] WITH CHECK ADD CONSTRAINT [FK_Persons_CourseBooks] FOREIGN KEY([AssignedToId])
REFERENCES [dbo].[Persons] ([PersonId])



INSERT INTO Schools (Name) values (N'Business'), (N'Education')
INSERT INTO Persons (Name, PersonType, SchoolId) values ('Eddy',1, 1), ('Fran',1, 1), ('Joe',2, 1), ('Kim',2, 1)
INSERT INTO Buildings (Name, GuardianId) values (N'Offsite staff', 1), (N'Main Business Building', 1)
INSERT INTO CourseBooks(AssignedToId, BookNumber) values (3, 'Course A book 1'),(3, 'Course C book 31')