如何解决“已经有与此连接相关联的开放数据读取器”

时间:2018-12-31 12:01:08

标签: c# mysql asp.net entity-framework

主要问题是,当Web应用程序启动到互联网时,当负载很高时,会引发异常,告知已经存在打开的数据读取器。

以下是我们使用的规格:

  • 实体框架5.0.0
  • MySQL数据库

如果没有using(){}块,是否有解决此问题的方法?这种方法的主要问题是,当关闭using块时,我无法在html视图内扩展entityframework对象的外键关系。

我还附加了一些源代码,展示了我们如何在整个应用程序中保持单个数据库上下文

public abstract class AbstractService
{
    public Entities db_model
    {
        get
        {
            return DbContext.Instance.db_model;
        }
    }
}

public class DbContext
{
    public Entities db_model = new Entities();
    private static DbContext _dbContext;

    public static DbContext Instance
    {
        get
        {
            if(_dbContext == null)
            {
                _dbContext = new DbContext();
            }
            return _dbContext;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

此答案与在ASP.NET视图中使用加载的实体的问题中提到的问题特别相关。该问题询问了一种无需using块或无需处理DbContext的情况下解决此问题的方法,但是我建议这样做。

原因是通常不希望在ASP.NET视图中使用Entity Framework对象,因为这些对象比普通的POCO对象要多得多。它们隐藏允许他们充当基础数据库代理的逻辑,因此它们对创建它们的DbContext的状态具有隐藏的依赖性。

这是一个使用EmployeeDepartment的EF模型使用EF模型的人为示例:

DbContext

如果在ASP.NET应用程序中使用这些模型,我将创建一些独立的模型,这些模型与ASP.NET使用的实体框架无关。例如:

public class CompanyDbContext : DbContext
{
    public DbSet<Department> Departments { get; set; }
    public DbSet<Employee> Employees { get; set; }
}

public class Department
{
    public long Id { get; set; }
    public virtual ICollection<Employee> Employees { get; set; }
}

public class Employee
{
    public long Id { get; set; }
    public long DepartmentId { get; set; }
    public virtual Department Department { get; set; }
}

一些注意事项:

  1. 根据MSDN文档,“ A public class DepartmentModel { public long Id { get; set; } public List<EmployeeModel> Employees { get; set; } } public class EmployeeModel { public long Id { get; set; } public long DepartmentId { get; set; } } 代表UnitOfWork和存储库模式的组合” -https://docs.microsoft.com/en-us/dotnet/api/system.data.entity.dbcontext?redirectedfrom=MSDN&view=entity-framework-6.2.0-因此,DbContext应该尽可能短命。

  2. 从上下文加载数据时,可以使用DbContext-https://docs.microsoft.com/en-us/ef/ef6/querying/related-data

  3. 检索相关实体
  4. 通常来说,出于各种原因,将“数据”层与“视图”层解耦是有意义的,其中一些原因在这里列出:https://docs.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5-这涉及EF对象和POCO模型之间的映射。

用于查询DbSet<>.Include()的逻辑将使用EF查询数据,并使用POCO模型返回该数据,以便只有直接处理DbContext的逻辑才涉及EF对象。 。例如:

DbContext

能够使用那些POCO模型,同时需要一些额外的样板代码,从而在 public List<DepartmentModel> GetAllDepartments() { using (var ctx = new CompanyDbContext()) { // Ensure that related data is loaded var departments = ctx.Departments .Include(d => d.Employees); // Manual mapping by converting into a new set of models to be used by the Views var models = departments .Select(d => new DepartmentModel { Id = d.Id, Employees = d.Employees .Select(e => new EmployeeModel { Id = e.Id, DepartmentId = e.DepartmentId }) .ToList(), }) .ToList(); return models; } } 和ASP.NET之间实现了完全分离,从而无需使用ASP.NET视图/控制器就可以使用数据。 DbContext的生存期或状态。

有时这看起来好像这种方法违反了“ DRY”原理,但是我要指出的是,存在EF对象和ViewModel对象可以解决不同的问题,并且ViewModel对象采用不同的形状并不少见,或者甚至需要其他不适合添加到EF类的字段/属性。

最后,以上代码使用“手动”映射,但是如果映射确实非常简单明了,则改为使用AutoMapper更为合理:Cleanest Way To Map Entity To DTO With Linq Select?