| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Базы данных под .NET > Статический обьект SqlConnection |
| Автор: thomas 17.5.2009, 14:56 | ||||
| Приветствую всех. Вот столкнулся с непонятной проблемой. Пишу приложение работающее с БД на MS SQL server. Для описания объектов использую статические классы, которые содержат статические методы для чтения/записи данных в БД. Поначалу каждый раз создавал новое соединение с БД. Статической использовал строку соединения.
Потом подумал что это не совсем правильно. Нужно один раз создать соединение и потом его использовать по мере необходимости (открывать/закрывать). Решил сделать не строку подключения статической, а весь объект соединения статическим. В умных книжках написано что C# гарантированно вызовет статический конструктор перед первым использование поля, свойства или метода статического класса. И потом можно постоянно его(поле например) использовать в других классах. Я попробовал создать статический объект типа SqlConnection. Сначала делал только статическое поле, а потом добавил статический конструктор и далее еще и метод.
Перед первым использованием он создается нормально. Все хорошо. Но вот когда надо второй раз использовать это соединение, оно теряет свое свойство connectionString. И вот в чем тут проблема мне никак не понять. Изменения вносимые к класс Verbinding к решению проблемы не привели. В принципе все осталось тем же самым, а запись увеличилась. Прошу подсказать или объяснить в чем я не прав. И как это исправить? Заранее спасибо. |
| Автор: Unlocker 17.5.2009, 15:28 | ||
А почему нельзя создать класс-singleton?
Смысл всего этого шаманства в том, что при первом обращении к классу объект-одиночка инициализируется, а затем к нему можно обращаться из любого места программы, не боясь ощутить потерю параметров инициализации. PS: мог где-то накосячить в синтаксисе, но без подстветки сложно набирать. Если интересно узнать про синглетон, то милости прошу открыть ставший уже классическим труд "банды четырех". Удачи |
| Автор: thomas 17.5.2009, 15:58 | ||||
| Unlocker, Приветствую. Сделал как ты посоветовал. Через свойство.
Но результат тот же. При первом использовании соединение создается, данные из БД считываются и отображаются на экране. Но при попытке сохранить изменения после редактирования данных или новой строки вылетает ошибка об отсутствии инициализации свойства connectionString для соединения. И действительно если использовать брейкпойнты то видно в первом случае свойство присвоено как и написано в конструкторе, а во втором случае оно пустое.
Вопрос, куда девается присвоенное ранее значение и почему это происходит? |
| Автор: Idsa 17.5.2009, 16:11 |
| thomas, видимо, где-то этому свойству присваивается значение пустой строки (в ходе или после выполнения первого запроса). Само по себе статическое свойство изменяться не может. |
| Автор: thomas 17.5.2009, 16:15 | ||
| Unlocker, Даже если в классе Verbinding написать только одно статическое поле
то один раз срабатывает на УРА, а при повторном использовании вылетает исключение. Куда то девается значение свойства ConnectionString у connection. Хотя аналогичную конструкцию я использовал и в другом проекте и там все было чики чики. Добавлено через 3 минуты и 9 секунд Idsa, Привет. Да уж интересно где и почему это происходит. Ведь по идее один раз созданный статический объект меняться не должен. Сам я его ни где не меняю. Мне надо только в нужный момент подсунуть его для создания команды и открыть/закрыть при её выполнении. И откуда, блин, растут ноги? |
| Автор: Idsa 17.5.2009, 16:20 |
| thomas, попробуй внимательно пройтись дебаггером и все-таки определить место, где меняется значение строки соединения. |
| Автор: thomas 17.5.2009, 17:25 |
| Idsa, Не найти. При последнем закрытии перед отрисовкой формы все нормально. После добавления нового элемента и попытке его сохранить в объекте соединение свойство утеряно. |
| Автор: Idsa 17.5.2009, 17:39 |
| thomas, можно попробовать закачать исходники .NET и поставить breakpoint на setter свойства ConnectionString. |
| Автор: Unlocker 17.5.2009, 18:28 | ||
| Вопрос реально интересный. При работе с ADO я делал DataSet приложения синглетоном: было очень удобно. Кстати, можно попробовать в геттере SqlConnection проставить инициализацию строкой подключения. Попробуй так:
Ну и, конечно, желательно пошагово дебаггером пройтись, чтобы посмотреть как изменяются переменные во время выполнения. |
| Автор: thomas 17.5.2009, 19:56 |
| Idsa, Unlocker, Из той же оперы вопрос. Я тут обнаружил что у меня по ходу пьесы одно соединение должно использоваться для разных команд одновременно. Объясняю на пальцах. Есть группа товаров, в ней различные категории, в категориях субкатегории , а в них уже товары. Так вот считываю данные на группу из БД, использую для этого СП и ДатаРидер. Соответственно соединение открыто. А группа то содержит категории, значиться для свойства категории объекта группа вызывается метод из класса категория для считывания данных из БД. И в этом методе должно использоваться тоже соединение, которое уже использует метод класса группа, но с другим объектом SqlCommand и StoredProcedure. Да еще оно(соединение) открыто. А тут по новой открывать. Экскпшен. Вопросец, а можно ли одно соединение использовать ОДНОВРЕМЕННО для разных объектов типа SqlCommand на основе разных StoredProcedure? |
| Автор: Unlocker 17.5.2009, 22:22 |
| thomas, ты правда не ответил по предыдущему вопросу. Работает ли класс таким свойством? А по второму вопросу: тут надо поэкспериментировать. Мне кажется, что один коннект можно использовать для разных команд. А вот открывать его по второму разу, как было замечено выше - вредно, т.к. исключение вылезает |
| Автор: PashaPash 18.5.2009, 14:09 | ||||
Правильно - создавать SqlConnection, открывать и закрывать для каждой операции, а не держать один синглтон. B противном случае поимеешь вот как раз те проблемы, что в предыдущих постах описаны. Добавлено через 3 минуты и 26 секунд
Создаешь SqlConnection, открываешь, выбираешь группы, закрываешь. Создаешь SqlConnection, открываешь, выбираешь категории, закрываешь. Чем плохо? |
| Автор: Idsa 18.5.2009, 14:13 | ||
О каких проблемах ты говоришь? О том, что "обнуляется" свойство ConnectionString? Ты думаешь, эта логика прошита в каком-то из методов класса SqlConnection? |
| Автор: PashaPash 18.5.2009, 14:24 | ||
Хз, где она там прошита, но я точно знаю что для SqlConnection Close and Dispose are functionally equivalent. Странно ожидать нормальной работы от диспоузнотого объекта. И, кстати, нет никакого смысла открывать надолго SqlConnection, в надежде получить бонус по скорости - это наоборот перечеркивает все фишки от pooling-a соединений. Там внутри все и так статическое. |
| Автор: Idsa 18.5.2009, 15:06 |
Судя по тому коду, который предоставил thomas, connection не диспозится, а просто открывается/закрывается. Так connection подолгу и не держится. Опять же, сужу по вышеприведенному коду: там соединение открывается до выполнения операции и закрывается сразу после завершения ее выполнения. А вообще интересно, что побудило thomas отойти от традиционного подхода с созданием SqlConnection через using при каждом запросе... Я тут насчет MARS подумал... пожалуй, не будет оно так работать. С открытием подключения и выполнением запроса все будет в порядке, но как только один из потоков вызовет Connection.Close, оставшиеся задачи выполнены не будут. MARS больше подходит для ситуаций, когда нужно в одном месте выполнять несколько запросов через одно соединение. |
| Автор: PashaPash 18.5.2009, 15:25 | ||||
А судя по MSDN - вызов Close эквивалентен вызову Dispose.
Жажда приключений? |
| Автор: Idsa 19.5.2009, 05:55 |
Это да... Я тут поигрался немного... ну никак мне не удается добиться того, чтобы само по себе "обнулялось" свойство ConnectionString. Вероятно, по этой же причине thomas игнорирует ORM |
| Автор: thomas 21.5.2009, 11:24 | ||||||||||||
| Приветствую всех. Была маленькая запара на сельскохозяйственной ниве, потому не мог выйти в сеть. Всем спасибо за обсуждение моей проблемы. Unlocker,
Idsa,
PashaPash,
Idsa,
Отвечаю сразу обоим. По мнению моего руководителя проекта, создание каждый раз объекта соединения с БД слишком накладная операция, а потому нужно иметь один раз созданный объект соединения и использовать его по мере необходимости. Возможно он и прав. Судите сами. Вот у меня только для того чтобы отобразить дерево Группа-Категории-Субкатегории в treeView и товары субкатегории в DataGridView нужно создать четыре соединения и сделать выборку данных. А если пользователей у программы не один, а с десяток. И далее для каждого действия с данными каждый раз создавать соединение по новой. Картина получается не вполне нормальная. Программа только и делает что создает соединения с БД. А если это все происходит не на локальном сервере в локальной сети, а через интернет? Так что PashaPash, правильно ли создавать SqlConnection и открывать/закрывать для каждой операции? Пока что я вернулся к своему первоначальному варианту, т.е. для каждой операции создание своего соединения. На следующей неделе буду общаться с преподом с глазу на глаз и спрошу про
Интересно что он скажет? Хотя с другой стороны. Вот сейчас в школе закончили семестр в котором работали небольшими группами над проектами. В нашем проекте мы с успехом смогли использовать одно соединение созданное статическим классом. Но там не было каскадных вызовов соединения. Внутри каждой операции был только вызов одной команды. Классы описывали только один объект и в них не было свойств содержащих дочерние объекты, как в моем проекте. Так что не все так однозначно. Похоже нужно глубже изучать этот вопрос и искать золотую середину. Добавлено через 2 минуты и 43 секунды Idsa,
|
| Автор: Idsa 21.5.2009, 11:28 | ||||
Программа лишь создает экземпляры класса SqlConnection, сами физические соединения поддерживаются connection pool'ом и не разрываются при каждом вызове SqlConnection.Close.
Так ее давно уже нашли. И имя ей - Connection Pool. |
| Автор: PashaPash 21.5.2009, 13:02 |
| thomas, вот линк с подробностями: http://msdn.microsoft.com/ru-ru/library/8xx3tyca.aspx |
| Автор: Idsa 21.5.2009, 13:05 |
Насколько я понял, ты реализуешь банальный DAL с CRUD-операциями. Все правильно? Если так, то для этих целей гораздо удобнее использовать ORM. |
| Автор: thomas 21.5.2009, 16:24 |
| Idsa, ORM - wat is dat? |
| Автор: Unlocker 21.5.2009, 16:37 |
Присоединяюсь к вопросу и прошу разъяснений. |
| Автор: Idsa 21.5.2009, 16:46 |
| http://ru.wikipedia.org/wiki/ORM Реализации под .NET: Entity Framework, NHibernate, LINQ To SQL... |