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;
}
}
Internal .Net Framework Data Provider error 1. при закрытии подключения
Есть класс:
Код:
В другом классе есть методы:
Код:
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;
}
{
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
Цитата: 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;
}
}
{
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++).
Цитата: 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
}
}
}
}
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
}
}
}
}
Конечно, контексты могут быть вложенными (при выходе из него переключается предыдущий).
Код:
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);
}
}
}
{
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, которую не возможно прочитать из-за того что там нет новых строк %)
Код:
using (new ResouceContext())
{
ResourceContext.Current.
}
{
ResourceContext.Current.
}
Код:
using (ResourceContext context = new ResourceContext())
{
context.
}
{
context.
}
Цитата: Der Meister
Вроде можно обойтись без контекстных синглтонов и, как следствие, без открытых статических методов/свойств
Но придется тогда передавать текущий контекст через аргументы всех методов - а это неудобно может быть. Статическое свойство удобнее, так как доступно отовсюду, и одновременно потоко-изолировано.
Просто, я так понял, что топикстартеру нужен был механизм, позволяющй получать объект соединения из немалого числа вложенных фунций, без передачи его через аргументы, плюс некий механизм безопасного управления этим ресурсом.
Код:
using (new ResouceContext()) {
... вызовы функций
ResourceContext.Current.
... возвраты из них
.... и еще всякий код
}
... вызовы функций
ResourceContext.Current.
... возвраты из них
.... и еще всякий код
}
Фактическое соединение к БД лучше открывать в момент первого обращения к объекту соединения:
Код:
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
}
}
}
}
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
}
}
}
}
Благодаря этому функции потеряли в строках кода до 30%. Огромное спасибо, все стало круто :D Жаль репутацию не могу добавлять, ибо слишком часто вы ее зарабатываете :)