以下代码使用Entity Framework 6和Managed Oracle Providers来调用返回多个游标的Oracle存储过程。
using
语句引发以下异常:
System.ObjectDisposedException: 'Cannot access a disposed object.Object name: 'OracleConnection'.'
如果我删除了using语句,而是使用以下帖子中的代码。我没有错误。
Using Entity Framework to Call an Oracle Stored Procedure with Multiple Cursors
为什么using语句导致异常?我建议Oracle托管提供程序存在错误。但是,我的同事使用的是同一提供程序,并且他们的using语句工作正常。
示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using Oracle.ManagedDataAccess.Client;
using System.Data.Entity.Infrastructure;
namespace MyCompany
{
public class MyClass
{
private MyDbContext _dbContext = new MyDbContext();
public MyItems GetMyItems(string id)
{
var sqlQuery = "";
var oracleParameters = new List<OracleParameter>();
var oneEntityList = new List<OneEntity>();
var twoEntityList = new List<TwoEntity>();
var threeEntityList = new List<ThreeEntity>();
sqlQuery = @"
BEGIN
MY_PACKAGE.GetMyItems(:id, :p_cursor1, :p_cursor2, :p_cursor3);
END;
";
oracleParameters = new List<OracleParameter>
{
new OracleParameter("p_id", id),
new OracleParameter("p_cursor1", OracleDbType.RefCursor, ParameterDirection.Output),
new OracleParameter("p_cursor2", OracleDbType.RefCursor, ParameterDirection.Output),
new OracleParameter("p_cursor3", OracleDbType.RefCursor, ParameterDirection.Output)
};
using (var connection = _dbContext.Database.Connection)
{
connection.Open();
var command = connection.CreateCommand();
command.CommandText = sqlQuery;
command.Parameters.AddRange(oracleParameters.ToArray());
using (var reader = command.ExecuteReader())
{
oneEntityList = ((IObjectContextAdapter)dbContext).ObjectContext
.Translate<OneEntity>(reader)
.ToList();
reader.NextResult();
twoEntityList = ((IObjectContextAdapter)dbContext).ObjectContext
.Translate<TwoEntity>(reader)
.ToList();
reader.NextResult();
threeEntityList = ((IObjectContextAdapter)dbContext).ObjectContext
.Translate<ThreeEntity>(reader)
.ToList();
}
return new MyItems { OneEntity = oneEntityList, TwoEntity = twoEntityList, ThreeEntity = threeEntityList };
}
}
}
}
答案 0 :(得分:5)
在拥有寿命的情况下,在一次性对象周围使用using
语句是正确和适当的;但是,在这种情况下:您不会!这里的连接属于数据上下文,并且假定数据上下文本身是IDisposable
,并且在放置数据上下文时,它将断开连接。
因此:虽然出于执行查询的目的,可能允许您从数据上下文中借用,但您不应在这里尝试处置 。最终将在意外的时间关闭/释放连接,结果无法预测。
相反:如果您有一个var conn = new OracleConnection(...)
,那么您显然要做拥有 that 连接(除非您将其交给可以管理生命周期的东西),并且您应该将其处置。
只是使事情变得更加复杂...当前,您的MyClass
似乎通过以下方式拥有数据库上下文:
private MyDbContext _dbContext = new MyDbContext();
因此,理想情况下,MyClass
应该是一次性的(: IDisposable
),处置MyClass
应该级联以处置_dbContext
。