我在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; }
}
以及相应的数据库设置:
现在我的问题。每当我执行FindProjectById
方法时,它确实会返回正确的对象,但它缺少对子项的任何引用。这意味着
ProjectSteps
EmployeesWorkingOnProject
ProjectLeader
未设定。这也会导致我的删除方法出现问题。我认为这是我的OnModelCreating
方法中的错误,但我不是100%肯定。
任何人都可以告诉我我还缺少什么来获取子对象吗?
答案 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,则需要在访问前加载引用。