System.ObjectDisposedException: 'Невозможно получить доступ к удаленному объекту. Имя объекта:' OracleConnection '.'

2

Следующий код использует Entity Framework 6 и управляемых провайдеров Oracle для вызова хранимой процедуры Oracle, которая возвращает несколько курсоров.

Оператор using выдает следующее исключение:

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

Если я удалю оператор using и вместо этого использую код в следующем посте. Я не получаю ошибок.

Использование Entity Framework для вызова хранимой процедуры Oracle с несколькими курсорами

Почему оператор using вызывает исключение? Мне было предложено, что есть ошибка с Oracle Managed Provider. Но мои коллеги используют одного и того же провайдера, и их заявления об использовании работают нормально.

Пример кода:

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

        }
    }
}
Теги:
entity-framework-6

1 ответ

5
Лучший ответ

Это правильно и уместно использовать с using заявлений вокруг одноразовых предметов, когда у вас есть время жизни; однако, в этом случае: нет! Соединение здесь относится к контексту данных, и, предположительно, сам контекст данных является IDisposable, и оно будет располагать соединением, когда располагается контекст данных.

Итак: хотя вам может быть разрешено заимствовать соединение из контекста данных для выполнения запросов - вы не должны пытаться его здесь разместить. Это может привести к закрытию/удалению соединения в неожиданное время с непредсказуемыми результатами.


И наоборот: если у вас была var conn = new OracleConnection(...), тогда вы явно владеете этим соединением (если только вы не var conn = new OracleConnection(...) его чему-то, что будет управлять временем жизни), и вы должны его утилизировать.


Просто, чтобы еще больше усложнить ситуацию... в настоящее время ваш MyClass кажется, владеет контекстом db через:

private MyDbContext _dbContext = new MyDbContext();

Поэтому в идеале ваш MyClass должен быть одноразовым (: IDisposable), а утилизация MyClass должна каскадно _dbContext.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню