使用 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有三种方式(不使用,动态使用,静态使用,默认是动态使用)