entity-framework - Entity Framework 上下文和结构图配置

标签 entity-framework asp.net-mvc-3 entity-framework-4.1 structuremap

我在 asp.net mvc 应用程序中处理 Entity Framework 连接时遇到奇怪的问题。

我有简单的结构,例如:

实体 :

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 - 接口(interface)
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();
    }

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

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

不幸的是我得到了经典的异常(exception):

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.



这很奇怪,因为在请求期间调用了服务,并且所有数据都被强制发送到 Controller 中的客户端......

任何想法,我在哪里做错了?

编辑 :

服务代码:
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();
    }

Controller :
    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();
    }


}   

最佳答案

您的代码不使用当前 DbContext一点也不。问题是:

IntranetSession.Current.LoggedAccount.Employee

其次是:
employee.OrganizationUnits.ToList()

您存储在 session 中的员工加载了已经处理的上下文,但它仍然保持对该上下文的引用。当您加载该员工时,您并不急于加载他的组织,因此一旦您访问她 OrganizationUnits它将尝试在已处置的上下文中触发延迟加载。

有两种方法可以避免这个问题:
  • 渴望从存储在 session 中的员工那里加载您需要使用的所有信息。这意味着检索像 context.Employees.Include(e => e.OrganizationUnits).Single(...) 这样的员工
  • 在 session 中仅存储员工的 ID 并按需加载您需要的数据

  • 如果您想在 session 中缓存整个员工,请确保您将通过调用禁用 session 中存储的对象的代理创建:
     context.Configuration.ProxyCreationEnabled = false;
    

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

    关于entity-framework - Entity Framework 上下文和结构图配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7341141/

    相关文章:

    c# - 绕过 Controller 中的模型验证?

    javascript - MVC 模型绑定(bind)无法通过 AJAX 请求工作

    entity-framework - 如何告诉 EF/DbSet 附加到 SQL View 而不尝试创建同名表?

    c# - 事务死锁,如何设计得当?

    .net - Azure表存储: questions regarding the structure of objects in a table

    c# - 在 OnModelCreating 中撤消 HasIndex

    c# - 使用聚合和分组依据的 LINQ 查询

    jquery - asp.net mvc3 razor 和 jquery 提交

    jquery - 查找与用户选择的 <li> 元素关联的数据

    c# - Entity Framework 代码优先 - 来自同一张表的两个外键