System.ObjectDisposedException:'无法访问已处置的对象。对象名称:'OracleConnection'。'

Posted

技术标签:

【中文标题】System.ObjectDisposedException:\'无法访问已处置的对象。对象名称:\'OracleConnection\'。\'【英文标题】:System.ObjectDisposedException: 'Cannot access a disposed object.Object name: 'OracleConnection'.'System.ObjectDisposedException:'无法访问已处置的对象。对象名称:'OracleConnection'。' 【发布时间】:2019-04-28 06:00:57 【问题描述】:

以下代码使用 Entity Framework 6 和托管 Oracle 提供程序来调用返回多个游标的 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 Managed Provider 存在错误。但是,我的同事使用的是同一个提供程序,并且他们的 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 ;
            

        
    

【问题讨论】:

【参考方案1】:

当你拥有生命周期时,在一次性对象周围使用using 语句是正确和正确的;但是,在这种情况下:你没有!这里的connection属于data-context,推测data-context本身就是IDisposable,在data-context被dispose的时候会dispose这个connection。

所以:虽然您可能被允许数据上下文中的连接以执行查询 - 您不应该尝试在此处处置它.这最终会在意外的时间关闭/释放连接,导致无法预料的结果。


相反:如果你有一个var conn = new OracleConnection(...),那么显然你确实拥有那个连接(除非你把它交给可以管理生命周期的东西),并且你应该处理掉它。


只是为了让事情进一步复杂化......目前,您的 MyClass 似乎拥有 db-context,通过:

private MyDbContext _dbContext = new MyDbContext();

因此,理想情况下,您的 MyClass 应该是一次性的 (: IDisposable),而处置 MyClass 应该级联处置 _dbContext

【讨论】:

以上是关于System.ObjectDisposedException:'无法访问已处置的对象。对象名称:'OracleConnection'。'的主要内容,如果未能解决你的问题,请参考以下文章