使用 ObjectDataSource.Select() 方法最终会导致异常“操作无法完成,因为 DbContext 已被释放。”

Posted

技术标签:

【中文标题】使用 ObjectDataSource.Select() 方法最终会导致异常“操作无法完成,因为 DbContext 已被释放。”【英文标题】:Usage of ObjectDataSource.Select() method eventually results to exception "The operation cannot be completed because the DbContext has been disposed." 【发布时间】:2013-11-29 18:59:22 【问题描述】:

我是 EF 和存储库模式的新手。我知道问题出在我的代码中,但我不确定什么是正确的解决方案。问题来了:

我有一个 WebForm,我在其中查询数据库以显示一条记录。我已经通过业务逻辑层 (BLL) 和数据库访问层 (DAL) 实现了。在 WebForm 中,我使用以下 ObjectDataSource:

<asp:ObjectDataSource ID="EmployerObjectDataSource" runat="server" TypeName="IkaManagerWeb.BLL.IkaMgrBL"
                      DataObjectTypeName="IkaManagerWeb.BLL.IkaMgrBL"
                      SelectMethod="GetEmployer"
                      OnSelecting ="EmployerObjectDataSource_Selecting">
    <SelectParameters>
        <asp:Parameter Name ="username" Type="String" />
        <asp:Parameter Name="version" Type="UInt16" />
    </SelectParameters>
</asp:ObjectDataSource>

因此,在 WebForm 背后的代码中,我执行以下操作:

    public partial class WebForm1 : System.Web.UI.Page
    
        private string _username;
        private short _version;

        protected void Page_Load(object sender, EventArgs e)
        
            _username = "Lefteris";
            _version = 1;

            if (!Page.IsPostBack)
            
                //  InputStyle style = txtFirstName.DisabledStyle;
                populateFields();
            
        

        protected void EmployerObjectDataSource_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)

        
            e.InputParameters["username"] = _username;
            e.InputParameters["version"] =_version;
            

        private bool populateFields()
        

            IEnumerable<Employer> empl = (IEnumerable<Employer>)EmployerObjectDataSource.Select();


            System.Threading.Thread.Sleep(1000);
            if (empl.Count() == 1)
            
                Employer employer = empl.First();
                txtAme.Text = employer.AME.ToString();
            ...

问题是我一上线:

if (empl.Count() == 1)

在上面,我得到一个异常,DBContext 已被释放。通过单步执行 BLL 和 DAL 中的代码,我看到 DBContext 确实被释放了。其实作为

EmployerObjectDataSource.Select(); 

返回结果,BLL 被释放,这反过来又导致 DAL 和 DBContext 被释放。

我认为的解决方案是在 PopulateFields 方法的整个执行过程中保持对 BLL 的引用。所以这里是问题:

这是正确的方法吗(可能使用“using”块)?如果是,那么我怎样才能获得对 BLL 的引用EmployerObjectDataSource 为执行 Select 实例化的对象

编辑:通过单步执行代码,我看到了以下事件顺序:

    通过调用 ObjectDataSource 的Select() 方法,实例化 BLL 对象。 BLL 正在实例化 DAL 对象。 DAL 对象正在执行底层数据库查询 BLL 正在输入Dispose() 在 BLL Dispose() 期间调用 DAL Dispose() - 这将删除 DBContext ObjectDataContext 的Select() 方法返回 只要我调用empl.Count(),就会枚举 empl 对象,并且由于 DBContext 已被删除,我得到了异常。

编辑:根据下面 Dmytro 的要求,我还提供了 BLL 的 GetEmployer 方法:

    public IEnumerable<Employer> GetEmployer(string username, short version)
    
        DateTime today = DateTime.Today;
        IEnumerable<Employer> employers = ikaRepository.GetEmployers(username, today, version);

        Debug.Assert(employers.Count() <= 1, "This is a logical Error - Can we have more than one active Employer records per user?");
        return employers;
    

请注意,这会正确检索记录。

提前谢谢你,

左撇子

【问题讨论】:

你是如何定义ObjectDataSoruce的查询的。在你的情况下,我认为你应该删除 using 块。` ` @SaeedNamati ObjectDataSource 将 BLL 中的函数用作 SelectMethod,而 BLL 又调用 DAL 中的方法。我目前没有使用任何 using 块。我将编辑帖子以显示事件的顺序,因为我已逐步完成。 【参考方案1】:

它看起来像你的线

IEnumerable<Employer> empl = (IEnumerable<Employer>)EmployerObjectDataSource.Select();

从 Select 方法返回 IQueryable 类型。此类型不包含真实数据,也不从 db 中获取数据。尝试使用类似的东西

var empl = ((IEnumerable<Employer>)EmployerObjectDataSource.Select()).ToList();

【讨论】:

谢谢你,但是,我仍然得到同样的异常(DBContext 已被删除) 还是一样的想法 - 将您的 IEnumerable 类型转换为 List 类型 ikaRepository.GetEmployers(username, today, version).ToList(); 一旦我可以访问开发机器,我稍后会尝试这个,但是,通过阅读 ObjectDataSource.Select 方法文档here,我知道 GetEmployers 应该返回以下之一类型:IEnumerable、DataTable、DataView、DataSet 或 Object(然后转换为 IEnumerable)。 List 实现了 IEnumerable,因此 Select() 方法将返回正确的数据类型。 这很好,解决了我的问题。查看文档,有第二种方法可以解决问题here。有趣的是,使用 Selected 事件可以在处理 BLL 对象之前处理返回的值:Select 操作完成后,调用 OnSelected 方法来引发 Selected 事件。您可以处理 Selected 事件以检查任何返回值、输出参数和异常,并执行任何后处理。

以上是关于使用 ObjectDataSource.Select() 方法最终会导致异常“操作无法完成,因为 DbContext 已被释放。”的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)