Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Internal .Net Framework Data Provider error 1. при закрытии подключения

408
15 апреля 2009 года
Lei fang
265 / / 01.10.2005
Здравствуйте. Появилась у меня такая странная проблема...
Есть класс:
Код:
public class SmartSQLConnection
    {
        private System.Data.SqlClient.SqlConnection connection;

        public SmartSQLConnection(string connection_string)
        {
            connection = new System.Data.SqlClient.SqlConnection(connection_string);
            try { connection.Open(); }
            catch (System.Exception e) { System.Diagnostics.EventLog.WriteEntry("Olimpic system - ConnectionMGR", e.Message); }
        }

        ~SmartSQLConnection()
        {
            connection.Close();
        }

        public System.Data.SqlClient.SqlConnection GetSQLConnection()
        {
            return connection;
        }
    }


В другом классе есть методы:
Код:
private SmartSQLConnection CreateSmartSQLConnection()
        {
            return new SmartSQLConnection(ConnectionString);
        }

        private object GetQueryResult(string QueryString, int QueryType)
        {
            System.Object ret = null;
            SmartSQLConnection smrt_con = CreateSmartSQLConnection();
            System.Data.SqlClient.SqlCommand com = new System.Data.SqlClient.SqlCommand(QueryString, smrt_con.GetSQLConnection());

            try
            {
                if (QueryType == 1) //select
                    ret = com.ExecuteReader();
                else if (QueryType > 1) //update, delete
                    ret = com.ExecuteNonQuery();
            }
            catch (System.Exception e) { System.Diagnostics.EventLog.WriteEntry("Olimpic system - QueryMGR", System.DateTime.Now.ToString() + ": " + QueryString + " / " + e.Message); }

            return ret;
        }


При первом же вызове метода GetQueryResult вылетает следующая вещь (приложена к теме)
Очень хочется сделать, чтобы подключение не надо было открывать и закрывать в телах функций. Чтоб это делалось само. Пока получется только открывать :D

Пробовал по разному, все одинаково. Толкьо если заккомментить connection.Close(); ошибки не будет.
Но подключение в этот момент открыто.

Есть у кого-нибудь идеи как сделать чтоб все было круто? :D
5
15 апреля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Lei fang
Есть у кого-нибудь идеи как сделать чтоб все было круто?


Черновой вариант:

Код:
public class SmartSQLConnection : IDisposable
    {
        private System.Data.SqlClient.SqlConnection connection;

        public SmartSQLConnection(string connection_string)
        {
            connection = new System.Data.SqlClient.SqlConnection(connection_string);
            try { connection.Open(); }
            catch (System.Exception e) { System.Diagnostics.EventLog.WriteEntry("Olimpic system - ConnectionMGR", e.Message); }
        }

        public void Dispose()
        {
            connection.Dispose();
        }

        public System.Data.SqlClient.SqlConnection GetSQLConnection()
        {
            return connection;
        }
    }
Использовать как:
 
Код:
using(SmartSQLConnection con = new SmartSQLConnection("blablabla")) {
// ... действия с БД
}
По выходу из блока соединение будет закрыто.

Не мешает почитать на тему реализации интерфейса IDisposable. Пример есть в МСДН, там же будет написано о финализаторе (имено его вы реализовали, когда думали что это деструктор в терминах C++).
5
15 апреля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Lei fang

Очень хочется сделать, чтобы подключение не надо было открывать и закрывать в телах функций. Чтоб это делалось само.


Можно организовать механизм контекстов:

Код:
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1 {

    public sealed class ResourceContext : IDisposable {

        public ResourceContext() {
            this._previous_context = _current_context;
            // TODO: захват ресурсов...

            _current_context = this;
        }

        ~ResourceContext() {
            Dispose(false);
        }

        [ThreadStatic]
        private static ResourceContext _current_context;

        /// <summary>
        /// Контекст ресуров в текущем потоке
        /// </summary>
        public static ResourceContext Current {
            get {
                if (!IsInitialized)
                    throw new InvalidOperationException("Context is not initialized.");
                return _current_context;
            }
        }

        private readonly ResourceContext _previous_context;

        /// <summary>
        /// Инициализирован ли контекст
        /// </summary>
        public static bool IsInitialized {
            get {
                return !ReferenceEquals(null, _current_context);
            }
        }

        private void Dispose(bool disposing) {
            if (disposing) {
                if (ReferenceEquals(this, _current_context)) {
                    _current_context = _previous_context;
                    // TODO: очистка ресурсов...

                } else {
                    throw new InvalidOperationException("Context can't be closed here.");
                }
            }
        }

        private bool _disposed = false;

        public void Dispose() {
            if (!_disposed) {
                Dispose(true);
                _disposed = true;
                GC.SuppressFinalize(this);
            }
        }
    }

    class Program {
        static void Main(string[] args) {
            using (new ResourceContext()) {
                // обращение к контексту
                // ResourceContext.Current.XXX
            }
        }
    }
}
ResourceContext создается к рамках текущего потока, далее все вызовы функций внутри блока using(new ResourceContext()) { } могут обращаться к статическому свойству ResourceContext.Current.

Конечно, контексты могут быть вложенными (при выходе из него переключается предыдущий).
408
15 апреля 2009 года
Lei fang
265 / / 01.10.2005
Я правильно сделал эту штуку с контекстом?
Код:
public sealed class ResourceContext : System.IDisposable
    {
        private System.Data.SqlClient.SqlConnection connection;

        public ResourceContext(string connection_string)
        {
            this._previous_context = _current_context;
            // TODO: захват ресурсов...
            connection = new System.Data.SqlClient.SqlConnection(connection_string);
            try { connection.Open(); }
            catch (System.Exception e) { System.Diagnostics.EventLog.WriteEntry("Olimpic system - ConnectionMGR", e.Message); }

            _current_context = this;
        }

        ~ResourceContext()
        {
            Dispose(false);
        }

        [System.ThreadStatic]
        private static ResourceContext _current_context;

        public System.Data.SqlClient.SqlConnection GetSQLConnection()
        {
            return connection;
        }

        public static ResourceContext Current //Контекст ресуров в текущем потоке
        {
            get
            {
                if (!IsInitialized)
                    throw new System.InvalidOperationException("Context is not initialized.");
                return _current_context;
            }
        }

        private readonly ResourceContext _previous_context;

        public static bool IsInitialized //Инициализирован ли контекст
        {
            get { return !ReferenceEquals(null, _current_context); }
        }

        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (ReferenceEquals(this, _current_context))
                {
                    _current_context = _previous_context;
                    // TODO: очистка ресурсов...
                    connection.Close();
                }
                else { throw new System.InvalidOperationException("Context can't be closed here."); }
            }
        }

        private bool _disposed = false;

        public void Dispose()
        {
            if (!_disposed)
            {
                Dispose(true);
                _disposed = true;
                System.GC.SuppressFinalize(this);
            }
        }
    }


Вообще ничего не понял, что и зачем тут, да и в инете совершенно ничего нет по "механизм контекстов", за исключением этой статьи http://rsdn.ru/article/dotnet/dotnetcontext.xml, которую не возможно прочитать из-за того что там нет новых строк %)
341
15 апреля 2009 года
Der Meister
874 / / 21.12.2007
Вроде можно обойтись без контекстных синглтонов и, как следствие, без открытых статических методов/свойств. То есть, можно
 
Код:
using (new ResouceContext())
{
    ResourceContext.Current.
}
привести к виду
 
Код:
using (ResourceContext context = new ResourceContext())
{
    context.
}
и, кажется, ничего не пострадает (при условии, что возможность создавать вложенные контексты будет сохранена) :)
5
15 апреля 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Der Meister
Вроде можно обойтись без контекстных синглтонов и, как следствие, без открытых статических методов/свойств

Но придется тогда передавать текущий контекст через аргументы всех методов - а это неудобно может быть. Статическое свойство удобнее, так как доступно отовсюду, и одновременно потоко-изолировано.

Просто, я так понял, что топикстартеру нужен был механизм, позволяющй получать объект соединения из немалого числа вложенных фунций, без передачи его через аргументы, плюс некий механизм безопасного управления этим ресурсом.

 
Код:
using (new ResouceContext()) {
... вызовы функций
    ResourceContext.Current.
... возвраты из них
.... и еще всякий код
}
[quote=Lei fang] Я правильно сделал эту штуку с контекстом?[/quote]
Фактическое соединение к БД лучше открывать в момент первого обращения к объекту соединения:
Код:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;

namespace ConsoleApplication1 {

    public sealed class ResourceContext : IDisposable {

        public ResourceContext(string connection_string) {
            this._previous_context = _current_context;
            // TODO: захват ресурсов...
            this._connection = new SqlConnection(connection_string);

            _current_context = this;
        }

        ~ResourceContext() {
            Dispose(false);
        }

        [ThreadStatic]
        private static ResourceContext _current_context;

        /// <summary>
        /// Контекст ресуров в текущем потоке
        /// </summary>
        public static ResourceContext Current {
            get {
                if (!IsInitialized)
                    throw new InvalidOperationException("Context is not initialized.");
                return _current_context;
            }
        }

        private readonly ResourceContext _previous_context;

        /// <summary>
        /// Инициализирован ли контекст
        /// </summary>
        public static bool IsInitialized {
            get {
                return !ReferenceEquals(null, _current_context);
            }
        }

        private readonly SqlConnection _connection;

        public SqlConnection Connection {
            get {
                if (_connection.State == System.Data.ConnectionState.Closed
                    || _connection.State == System.Data.ConnectionState.Broken)
                    _connection.Open();
                return _connection;
            }
        }

        private void Dispose(bool disposing) {
            if (disposing) {
                if (ReferenceEquals(this, _current_context)) {
                    _current_context = _previous_context;
                    // TODO: очистка ресурсов...
                    _connection.Dispose();
                } else {
                    throw new InvalidOperationException("Context can't be closed here.");
                }
            }
        }

        private bool _disposed = false;

        public void Dispose() {
            if (!_disposed) {
                Dispose(true);
                _disposed = true;
                GC.SuppressFinalize(this);
            }
        }
    }

    class Program {
        static void Main(string[] args) {
            using (new ResourceContext("bla bla bla")) {
                // первое обращение к контексту за соединением
                // приведет к открытию соединения с БД:
                // ResourceContext.Current.Connection
            }
        }
    }
}
408
16 апреля 2009 года
Lei fang
265 / / 01.10.2005
Благодаря этому функции потеряли в строках кода до 30%. Огромное спасибо, все стало круто :D Жаль репутацию не могу добавлять, ибо слишком часто вы ее зарабатываете :)
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог