C#EF6映射未应用于select

时间:2018-04-28 00:11:39

标签: c# .net entity-framework orm entity-framework-6

我在EF6中遇到Fluent API映射的问题。它已全部设置完毕,但出于某种原因,只要我选择一个对象,它就会丢失子对象。

让我们从DbContext开始:

public partial class PMSContext : DbContext
{
    public PMSContext() : base(nameOrConnectionString: "PmsDb")
    {
        this.Configuration.ProxyCreationEnabled = false;
        this.Configuration.LazyLoadingEnabled = false;
    }

    public DbSet<Employee> employees { get; set; }
    public DbSet<Project> projects { get; set; }
    public DbSet<ProjectStep> projectSteps { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        modelBuilder.Entity<Employee>().HasMany(e => e.Projects).WithMany(t => t.EmployeesWorkingOnProject).Map(m =>
        {
            m.MapLeftKey("EmployeeId");
            m.MapRightKey("ProjectId");
            m.ToTable("employee_project");
        });

        modelBuilder.Entity<ProjectStep>().HasRequired(p => p.Project).WithMany(s => s.ProjectSteps).Map(m => m.MapKey("Project")).WillCascadeOnDelete(true);
        //modelBuilder.Entity<Project>().HasMany(p => p.ProjectSteps).WithRequired(ps => ps.Project).WillCascadeOnDelete(true);

        modelBuilder.Entity<Employee>().HasOptional<Project>(e => e.LeaderOfProject).WithOptionalPrincipal(p => p.ProjectLeader).Map(m => m.MapKey("ProjectLeader"));

    }

    public Project FindProjectById(int id)
    {
        return this.projects.Find(id);
    }
}

这几乎是我所需要的所有内容。

我总共设置了3个模型类:

[DataContract(Namespace = "Shared")]
public class Employee
{
    public Employee()
    {
        this.Projects = new List<Project>();
    }

    [DataMember]
    public int ID { get; set; }

    [DataMember]
    public String Name { get; set; }

    [DataMember]
    public String JobDescription { get; set; }

    [DataMember]
    public String Department { get; set; }

    [DataMember]
    public String DirectDialing { get; set; }

    [DataMember]
    public bool Status { get; set; }

    public virtual Project LeaderOfProject { get; set; }

    [DataMember]
    public virtual List<Project> Projects { get; set; }
}

[DataContract(Namespace = "Shared")]
public class Project
{

    public Project()
    {
        this.EmployeesWorkingOnProject = new List<Employee>();
        this.ProjectSteps = new List<ProjectStep>();
    }

    [DataMember]
    public int ID { get; set; }

    [DataMember]
    public String Titel { get; set; }

    [DataMember]
    public DateTime StartDate { get; set; }

    [DataMember]
    public DateTime EndDate { get; set; }

    [DataMember]
    public String Description { get; set; }

    [DataMember]
    public Employee ProjectLeader { get; set; }

    [DataMember]
    public bool Status { get; set; }

    [DataMember]
    public virtual List<Employee> EmployeesWorkingOnProject { get; set; }

    [DataMember]
    public virtual List<ProjectStep> ProjectSteps { get; set; }
}

[DataContract(Namespace = "Shared")]
[Table("project_step")]
public class ProjectStep
{
    [DataMember]
    public int ID { get; set; }

    [DataMember]
    public String Description { get; set; }

    [DataMember]
    public DateTime StartDate { get; set; }

    [DataMember]
    public DateTime EndDate { get; set; }

    [DataMember]
    public Project Project { get; set; }
}

以及相应的数据库设置:

enter image description here

现在我的问题。每当我执行FindProjectById方法时,它确实会返回正确的对象,但它缺少对子项的任何引用。这意味着

  • ProjectSteps
  • EmployeesWorkingOnProject
  • ProjectLeader

未设定。这也会导致我的删除方法出现问题。我认为这是我的OnModelCreating方法中的错误,但我不是100%肯定。

任何人都可以告诉我我还缺少什么来获取子对象吗?

2 个答案:

答案 0 :(得分:1)

您已禁用延迟加载和代理,但如果您没有.Include()子实体,则EF不知道加载它们。要使用.Include(),您需要使用.SingleOrDefault()而不是Find。否则,您将需要转到上下文来加载子集合/引用。

您的FindProjectById()看起来像:

var project = this.Projects.Include(x=>x.ProjectLeader)
  .Include(x=>x.EmployeesWorkingOnProject)
  .Include(x=>x.ProjectSteps)
  .SingleOrDefault(x=>x.ID == id); 
return project; 

使用SingleOrDefault vs. Find的一个警告是,Find将搜索本地存储,然后转到DB,Single / First /等将转到DB。这意味着每次Find都可以在本地内存存储中找到实​​体时执行查询。如果要将记录插入到数据库上下文中(并且在保存更改之前),搜索该实体将不会返回本地存储中的实体,但尚未提交到该数据库。 (在SaveChanges()之前)

通常,您不希望返回DbContext范围之外的实体,因为延迟加载代理将不起作用,因此您未预加载的任何内容都将是#null。我通常依赖于延迟执行,然后返回IQueryable。选择()我关心的各种位到DTO / ViewModel POCO类中。

答案 1 :(得分:0)

如果要自动加载子对象,可以尝试将延迟加载更改为 true

this.Configuration.LazyLoadingEnabled = true;

如果延迟加载为false,则需要在访问前加载引用。