实体框架包括每个层次表的派生类型的关系

时间:2017-11-21 12:57:31

标签: c# entity-framework

如何Include集合类型为每个层次结构表设计的集合上的属性关系,以及在延迟加载禁用的派生类型上定义关系?

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

尝试和错误

我已尝试使用OfType但收到此消息。

  

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

我尝试使用as但收到此错误

  

System.InvalidOperationException - 指定的包含路径无效。 EntityType' Sandbox.TPHMcve.Person'不会声明名称为' Buildings'。

的导航属性

实施例

请不要关注这个愚蠢的例子的商业细节,这是一个说明我收到的错误的mcve。我的实际项目与学校/学校系统等无关。

结构

  • 大学的一所学校有人
  • 某人是学生或教师
  • 学生租借零课程或更多课程
  • 教师可被指定为一个或多个校园建筑的照顾者/监护人

代码

SchoolService.cs

这是产生例外的实际感兴趣的代码

public sealed class SchoolService
{
    private readonly UniversityDbContext _dbContext;
    public SchoolService(UniversityDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public School GetSchoolAndPeopleWithDetails_OfType(int schoolId)
    {
        return _dbContext.Schools.Where(x => x.SchoolId == schoolId)
            .Include(x => x.EntitiesOfSchool.OfType<Teacher>().Select(y => y.Buildings))
            .Include(x => x.EntitiesOfSchool.OfType<Student>().Select(y => y.BooksOnLoan))
            .SingleOrDefault();
    }
    public School GetSchoolAndPeopleWithDetails_Cast(int schoolId)
    {
        return _dbContext.Schools.Where(x => x.SchoolId == schoolId)
            .Include(x => x.EntitiesOfSchool.Select(y => (y as Teacher).Buildings))
            .Include(x => x.EntitiesOfSchool.Select(y => (y as Student).BooksOnLoan))
            .SingleOrDefault();
    }
}

Entities.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; }
}

EntityMappings.cs 不包含Building或CourseBook映射类型,因为它们不相关

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

UniversityDbContext.cs

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

表DDE的SQL代码和data.sql的种子

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')

0 个答案:

没有答案