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

c# entity-framework-6 oracle

Question

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

        }
    }
}
1
2
11/26/2018 3:05:53 PM

Accepted Answer

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.

5
11/26/2018 3:10:49 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow