1. В таком случае переменную SqlConnection нужно объявлять до блока try.
2. Если SqlConnection обернут в using то в finally нет никакого смысла connection будет disposed при выходе из блока using.
3. Вы finally неправильно написали
Re[3]: Грамотно обработать исключения при работе c SQL Serve
Здравствуйте, Pavel M., Вы писали:
PM>что вы имеете в виду?
public class MyCollection : IEnumerable<MyItem>
{
public IEnumerable<MyItem> Sort(string Value)
{
foreach(MyItem item in this)
{
if(item.MyProperty == Value)
yield return item;
}
}
}
MyCollection collection = new MyCollection();
foreach (MyItem item in collection.Sort("MyValue"))
{
//Do something
}
По моему здесь без объяснений понятно, что делает метод Sort, Это я и называю наглядностью. Причем итераторы могут быть любой сложности (кроме некоторых исключений), и при этом проход по коллекции осуществляется только один раз.
Re[4]: Грамотно обработать исключения при работе c SQL Serve
Здравствуйте, kostya.misura, Вы писали:
KM>Если использовать 2-й вариант, то надо будет в начале тела цикла ставить command.Parameters.Clear(); Ибо иначе вы добавите в комманду несколько параметров с одинаковыми именами. Что же касается performance — если команда исполняется >1 раза, имхо, предпочтительнее первый вариант, ибо во втором происходит при каждом проходе цикла больше действий, чем в первом, но думаю это не особо существенно.
Остановился на варианте с заданием типов параметров до цикла + cmd.Prepare(). В результате время заливки в локальную базу 1 млн. записей сократилось с 10 до 2 минут, что уже совсем хорошо!
Теперь возникла новая задача — но это уже отдельная тема
Re[6]: Грамотно обработать исключения при работе c SQL Serve
Здравствуйте, Sinclair, Вы писали:
S>Скорее всего, самый быстрый способ — сделать 100 запросов к базе данных. Затраты на это будут пропорциональны log(N), где N — общее количество файлов, а затраты на подъем всей таблицы в память — O(N).
Так и сделал. (учитывая также, что в перспективе число обработанных файлов в таблице будет расти).
Re[3]: Грамотно обработать исключения при работе c SQL Serve
Здравствуйте, fmiracle, Вы писали:
F>Есть где-нибудь, какое-нибудь требование стандарта, по которому не закоммиченная транзация при Dispose делает Rollback?
Даже если и не сделает (например, по причине обрыва связи), то ее все равно сделает сервер.
Берем рефлектор и смотрим код SqlTransaction.Dispose():
/// <summary>Releases the unmanaged resources used by the <see cref="T:System.Data.Common.DbTransaction"></see>.</summary>
/// <filterpriority>1</filterpriority>public void Dispose()
{
this.Dispose(true);
}
Здравствуйте, Ranger_XL, Вы писали:
R_X>Итак, у нас есть таблица БД, где хранятся имена уже обработанных файлов (десятки тысяч штук). Нам дан список новых файлов (около 100 штук). Надо исключить из списка те файлы, которые уже хранятся в таблице (таких может быть до 70%).
R_X>Пока видится 2 варианта: R_X>1) 100 запросов к БД в цикле (для каждого нового файла) R_X>2) прочитать всю таблицу из БД в память и сделать отбраковку локально
Извиняюсь, проглючило — теперь на свежую голову понял вопрос. Вот нормальное решение без 100...N запросов, а всего лишь с одним:
Таблица:
create table ИменаФайлов(
Имя nvarchar(256) primary key clustered
)
ХП возвращающая имена файлов которых нет в таблице:
set ansi_nulls, quoted_identifier on
create proc ВозвратитьИменаКоторыхНетВТаблице(
@xml ntext
)
as begin
set nocount on
declare @hdoc int, @ret_code int
exec @ret_code = dbo.sp_xml_preparedocument @hdoc output, @xmldoc
if @ret_code != 0
return @ret_code
select
Имя
from
openxml(@hdoc, '/root/child::*') with(
ИмяДляПроверки nvarchar(256) '@И',
) as Вход
where
not exists(
select
null
from
dbo.ИменаФайлов иф
where
иф.Имя = Вход.ИмяДляПроверки
)
;
exec dbo.sp_xml_removedocument @hdoc
end
Клиентский код:
// Имеем на входе:
// _СоедБД - соединение с базой данных
// _Файлы - список файлов для проверки
// Возвращаемый результат:
// остаются только те, которых нет в БД
List<string> ПроверкаИменФайловНаНаличиеВБазе(SqlConnection _СоедБД, List<string> _Файлы)
{
SqlCommand com = new SqlCommand("dbo.ВозвратитьИменаКоторыхНетВТаблице", _СоедБД);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.Add("@xml", SqlDbType.NText);
StringBuilder xml = new StringBuilder("<?xml version=\"1.0\"?><root>", 32768);
foreach (string Файл in _Файлы)
{
xml.Append("<с И=\"");
xml.Append(Файл);
xml.Append("\"/>");
}
xml.Append("</root>");
List<string> ReturnList = new List<string>(_Файлы.Count);
com.Parameters["@xml"].Value = xml.ToString();
using (SqlDataReader reader = com.ExecuteReader(CommandBehavior.SingleResult))
{
while (reader.Read())
{
ReturnList.Add((string)reader["Имя"]);
}
}
return ReturnList;
}
Такой код эффективней, чем 100 и более запросов. А на 1000 и более, он просто рвет как Тузик грелку — на несколько порядков.
Re[6]: Грамотно обработать исключения при работе c SQL Serve
ХП возвращающая имена файлов которых нет в таблице:
set ansi_nulls, quoted_identifier onGOcreate proc ВозвратитьИменаКоторыхНетВТаблице(
@xml ntext
)
as begin
set nocount on
declare @hdoc int, @ret_code int
exec @ret_code = dbo.sp_xml_preparedocument @hdoc output, @xml
...
Re[6]: Грамотно обработать исключения при работе c SQL Serve
Здравствуйте, Sinclair, Вы писали:
S>Скорее всего, самый быстрый способ — сделать 100 запросов к базе данных. Затраты на это будут пропорциональны log(N), где N — общее количество файлов.
Кстати, а почему затраты будут O(log N)?
Re[7]: Грамотно обработать исключения при работе c SQL Serve
Здравствуйте, fmiracle, Вы писали: F>Я когда-то тоже делал просто using, используя OleDBProvider для какой-то базы (точно не помню, кажется — DB2 была это)... А потом в том же проекте переключился на использование ее родного драйвера, который при диспозе незакоммиченной транзации делал — ха — коммит! F>Я сперва не поверил, проверял Рефлектором Да, действительно делал коммит.
Разработчикам этого чуда надо оторвать рабочие конечности.
Не устаю поражаться дефициту здравого смысла в природе!
Пояснения: с точки зрения кода, транзакция должна иметь четко очерченные границы. Крайне нежелательно иметь расхождения структуры кода и структуры транзакций, т.е. к примеру если какая-то бизнес-функция при возврате оставляет незакрытую транзакцию.
При этом как правило имеет смысл трактовать любое необработанное исключение, порожденное в процессе выполнения транзакции, ошибочной ситуацией. Значит, изменения, которые были произведены в транзакции, не являются валидными, поэтому транзакцию нужно откатывать. Только в том случае, если ошибок не возникло, можно считать, что транзакция успешна.
Поэтому типичный код работы с транзакцией выглядит так:
К сожалению, в современных языках нет способа описать "блок, который выполняется только если в защищенном блоке исключений не произошло". Зато можно считать, что "последний оператор в защищенном блоке" и есть такой "блок" — потому, что возникшее до него исключение приведет к выходу из блока.
Поэтому Commit и выполняют в конце блока try.
Далее, безусловный catch — не самое удобное место для rollback transaction. Потому, что могут быть и другие catch(), и в них придется дублировать логику отката. Поэтому в тех языках, где это возможно, применяют и менее красивую, но более надежную конструкцию:
Шарп мало того, что предоставляет блок finally, он еще и позволяет заранее, в начале защищаемого блока "заказать" исполнение finally при помощи конструкции using(). Это означает, что в Transaction.Dispose() можно и нужно делать только Rollback! Смысла делать Commit — нету никакого, т.к. это не ведет к сокращению кода.
Сравним код с Dispose == Rollback:
using(Transaction t = connection.BeginTransaction)
{
...
t.Commit();
}
Этот код еще корявее, чем для случая отсутствия управления транзакцией в Dispose.
1.2.0 alpha rev. 655
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Грамотно обработать исключения при работе c SQL Server
От:
Аноним
Дата:
12.01.07 05:05
Оценка:
Самый неясный момент для меня сейчас: как грамотно организовать обработку исключений (и запись их в журнал!) при работе с SQL server
и при этом освободить ресурсы (connection) в случае ошибки?
Это делается классическим способом
try
{
}
catch(SqlException exc)
{
}
finally
{
conn.Close();
}
Хочу заметить, что в Вашем коде есть ошибка. Никогда нельзя перехватывать исключения общего типа. Программист всегда должен знать, какие типы исключений он в данном месте отлавливает.
Вызывает сомнение использование константы DBCONNECTION_STRING для хранения строки подключения. Строки подключения надо хранить в Settings.
Также считаю, что на C# для обхода элементов конкретезированного списка логичнее использовать foreach, а не цикл for.
Согласен с утверждением, что вместо конкатенации строк надо использовать параметризированные запросы. Это все есть стиль хорошего программирования. Но в Вашем случае можно использовать хранимую процедуру. Будет быстрее и трафик меньше
И Если Вас не затруднит, подскажите, пожалуйста, а чем вызвана необходимость вот такой конструкции:
try {
transaction.Rollback ();
}
catch (Exception ex2) {
LogMessage ("WriteRecordsToDB(): transaction.Rollback() failed.", ex2);
}
Почему нельзя сделать просто
transaction.Rollback ();
Re[4]: Грамотно обработать исключения при работе c SQL Serve
От:
Аноним
Дата:
12.01.07 07:50
Оценка:
Итак, у нас есть таблица БД, где хранятся имена уже обработанных файлов (десятки тысяч штук). Нам дан список новых файлов (около 100 штук). Надо исключить из списка те файлы, которые уже хранятся в таблице (таких может быть до 70%).
Пока видится 2 варианта:
1) 100 запросов к БД в цикле (для каждого нового файла)
2) прочитать всю таблицу из БД в память и сделать отбраковку локально
Все намного проще. На сиквел сервере создается
временная таблица со списком файлов (100 имен) и делается INNER JOIN к таблице с файлами.