3

我在asp.net mvc应用程序中配置实体框架连接时出现了奇怪的问题。实体框架上下文和结构映射图

我有例如结构简单:

实体:

public class EmployeeReport 
{ 
    public int EmployeeReportId { get; set; } 

    public DateTime Created { get; set; } 

    public Decimal Hours { get; set; } 

    public string Comment { get; set; } 

    public int EmployeeId { get; set; } 

    public int ContractId { get; set; } 

    public int ServiceId { get; set; } 

    public virtual ReportContract Contract { get; set; } 

    public virtual ReportService Service { get; set; } 

    public virtual Employee Employee { get; set; } 

} 

实体映射:

public class EmployeeReportMapper : EntityTypeConfiguration<EmployeeReport> 
{ 
    public EmployeeReportMapper() 
    { 
     ToTable("intranet_employee_reports"); 
     HasKey(x => x.EmployeeReportId); 

     Property(x => x.Created).HasColumnName("Created").IsRequired(); 
     Property(x => x.Comment).HasColumnName("Comment").IsOptional(); 
     Property(x => x.Hours).HasColumnName("Hours").IsRequired(); 

     HasRequired(x => x.Employee).WithMany().HasForeignKey(x => x.EmployeeId); 
     HasRequired(x => x.Service).WithMany().HasForeignKey(x => x.ServiceId); 
     HasRequired(x => x.Contract).WithMany().HasForeignKey(x => x.ServiceId); 
    } 
} 

的DbContext - 接口

public interface IDbContext : IDisposable 
{ 
    IDbSet<EmployeeReport> EmployeeReports { get; } 
} 

的DbContext - 实现

public class IntranetDbContext : DbContext,IDbContext 
{ 
    public IDbSet<EmployeeReport> EmployeeReports { get; set; } 
    ... 


    public IntranetDbContext() : base("IntranetDb") 
    { 
     Database.SetInitializer<IntranetDbContext>(null); 
    } 

    public void Commit() 
    { 
     SaveChanges(); 
    } 

    public void ChangeEntityState(object entity, EntityState entityState) 
    { 
     Entry(entity).State = entityState; 
    } 

    public void ExecuteSql(string query, SqlParameterCollection parameterCollection) 
    { 
     Database.ExecuteSqlCommand(query, parameterCollection); 
    } 


    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     /* Register custom mapping class */ 
     modelBuilder.Configurations.Add(new EmployeeReportMapper()); 
     .... 
     base.OnModelCreating(modelBuilder); 
    } 

} 

最后我的结构映射配置:

public class CoreRegistry : Registry 
{ 
    public CoreRegistry() 
    { 
     For<IDbContext>().HttpContextScoped().Use<IntranetDbContext>(); 
     ... 
    } 
} 

和Global.asax中:

protected void Application_EndRequest(object sender, EventArgs e) 
    { 
     ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects(); 
    } 

好了,现在的问题,在我的应用程序使用标准的构造函数依赖注入 或致电ObjectFactory.GetInstance()。

在我的一个控制器中,我调用服务类,它可以访问dbcontext并获取一些实体。

不幸的是我得到的经典例外:

的ObjectContext的实例已设置,并且可以不再使用 为需要连接的操作。

这是奇怪的,因为服务请求期间调用,所有的数据都被迫在控制器客户端...

任何想法,我哪里错了吗?

编辑:

服务代码:

public class EmployeeService : IEmployeeService 
{ 
    /// <summary> 
    /// IDbContext reference 
    /// </summary> 
    private readonly IDbContext _dbContext; 

    public EmployeeService(IDbContext dbContext) 
    { 
     _dbContext = dbContext; 
    } 

    public List<Employee> GetSubordinateEmployees(Employee employee) 
    { 
     List<Employee> employees = new List<Employee>(); 

     foreach (var unit in employee.OrganizationUnits.ToList()) /* throw exception*/ 
     { 
      foreach (var childrenUnit in unit.ChildrenUnits) 
      { 
       employees.AddRange(childrenUnit.Employees); 
      } 
     } 
     return employees.Distinct().ToList(); 
    } 

控制器:

private readonly IEmployeeService _employeeService; 

    public EmployeeReportController(IEmployeeService employeeService) 
    { 
     _employeeService = employeeService; 
    } 

    [HttpGet] 
    public ActionResult SearchReports() 
    { 
     List<Employee> employees = _employeeService.GetSubordinateEmployee(IntranetSession.Current.LoggedAccount.Employee).ToList(); // Exception! 
     ... 

     return View(); 
    } 


} 
+0

显示实际导致异常被抛出的代码以及实际使用ObjectContext的代码。 –

+0

已添加控制器和服务代码 – Mennion

回答

1

你的代码不使用当前DbContext可言。问题是:

IntranetSession.Current.LoggedAccount.Employee 

其次:

employee.OrganizationUnits.ToList() 

你存储在会话雇员被加载与已经配置方面,但它仍然保持参照该上下文。当您加载该员工时,您并不急于加载他的组织,因此,一旦您访问她的OrganizationUnits,它将尝试在处置的上下文中触发延迟加载。

有两种方法来避免这个问题:

  • 渴望负载需要从存储在会话你的员工使用的所有信息。这意味着检索员工是什么样context.Employees.Include(e => e.OrganizationUnits).Single(...)
  • 商店只有雇员的ID在会话和负载需求的数据,你需要

如果你想缓存整个员工在会议上确认,你将禁用对象中存储的代理创建会议通过调用:

context.Configuration.ProxyCreationEnabled = false; 

这将确保缓存数据不会保留参考处置上下文(顺便说一句防止垃圾收集器收集上下文及其所有引用的对象)。

+0

您是对的,在我的init会话代码中,我使用include获取数据,但忘记了为员工提取组织单位。如果我显式调用LoggedAccount.Employee.OrganizationUnits.ToListI();在init代码中,应用程序起作用。感谢您的指导。 – Mennion