簡體   English   中英

如何解決“已經有一個與此連接關聯的打開的數據讀取器”

[英]How to solve "there is already an open datareader associated with this connection"

主要問題是,當 Web 應用程序啟動到 Internet 時,當負載很高時會引發異常,表明已經打開了數據讀取器。

以下是我們使用的規格:

  • 實體框架 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;
        }
    }
}

此答案與有關在 ASP.NET 視圖中使用加載的實體的問題中提到的問題特別相關。 該問題詢問了一種無需using塊或處理DbContext即可解決此問題的using ,但是我建議完全這樣做。

原因是通常不希望在 ASP.NET 視圖中使用實體框架對象,因為這些對象不僅僅是普通的 POCO 對象; 它們隱藏了允許它們充當底層數據庫代理的邏輯,因此它們對創建它們的DbContext的狀態具有隱藏的依賴性。

這是一個人為的示例,使用 EF 模型為EmployeeDepartmentDbContext

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; }
}

如果在 ASP.NET 應用程序中使用這些,我將創建一些與實體框架無關的單獨模型,供 ASP.NET 使用。 例如:

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; }
}

幾點考慮:

  1. 根據 MSDN 文檔, DbContext表示 UnitOfWork 和存儲庫模式的組合” - https://docs.microsoft.com/en-us/dotnet/api/system.data.entity.dbcontext?redirectedfrom=MSDN&view= entity-framework-6.2.0 - 因此DbContext應該盡可能短。

  2. 從上下文加載數據時,可以使用DbSet<>.Include()檢索相關實體 - https://docs.microsoft.com/en-us/ef/ef6/querying/related-data

  3. 一般來說,將“數據”層與“視圖”層分離是有意義的 - 出於各種原因,其中一些列在此處: https : //docs.microsoft.com/en-us/aspnet /web-api/overview/data/using-web-api-with-entity-framework/part- 5——這涉及EF對象和POCO模型之間的映射。

用於查詢DbContext的邏輯將使用 EF 查詢數據,並使用 POCO 模型返回該數據,以便只有直接處理DbContext邏輯才與 EF 對象有關。 例如:

    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;
        }
    }

能夠使用這些 POCO 模型,同時需要一些額外的樣板代碼,提供了DbContext和 ASP.NET 之間的完全分離,允許在 ASP.NET 視圖/控制器不關心DbContext的生命周期或狀態的情況下使用DbContext

有時這看起來好像這種方法違反了“DRY”原則,但是我要指出 EF 對象和 ViewModel 對象的存在是為了解決不同的問題,並且 ViewModel 對象采用不同的形狀,甚至要求不適合添加到 EF 類的其他字段/屬性。

最后,上面使用了“手動”映射,但如果映射真的簡單明了,那么使用 AutoMapper 會更有意義: Cleanest Way To Map Entity To DTO With Linq Select?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM