简体   繁体   中英

System.ObjectDisposedException: 'Cannot access a disposed object.Object name: 'OracleConnection'.'

The following code uses Entity Framework 6 and Managed Oracle Providers to call an Oracle stored procedure that returns multiple cursors.

The using statement is throwing the following exception:

 System.ObjectDisposedException: 'Cannot access a disposed object.Object name: 'OracleConnection'.'

If I remove the using statement and instead use the code in the following post. I get no errors.

Using Entity Framework to Call an Oracle Stored Procedure with Multiple Cursors

Why is the using statement causing an exception? It has been suggested to me that there is a bug with the Oracle Managed Provider. But, my colleagues are using the same provider and their using statements are working fine.

Example Code:

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

        }
    }
}

It is correct and proper to use using statements around disposable objects when you own the lifetime ; however, in this case: you don't! The connection here belongs to the data-context, and presumably the data-context itself is IDisposable , and it will dispose the connection when the data-context is disposed.

So: while you might be allowed to borrow the connection from the data-context for the purposes of executing queries - you shouldn't be trying to dispose it here. That would end up closing/disposing a connection at unexpected times, with unpredictable results.


Conversely: if you had a var conn = new OracleConnection(...) , then clearly you do own that connection (unless you hand it to something that will manage the lifetime), and you should dispose it.


Just to complicate things further... currently, your MyClass seems to own the db-context, via:

private MyDbContext _dbContext = new MyDbContext();

So ideally, your MyClass should be disposable ( : IDisposable ), and disposing MyClass should cascade to dispose _dbContext .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM