Добрый день.
Хочу посоветоваться с уважаемыми коллегами по следующему вопросу.
Некоторое время назад передо мной была поставлена задача написать программу,
осуществляющую пакетное преобразование файлов из внутреннего
формата некоторого приложения X в БД MSSQL Server. Обстоятельства
функционирования таковы, что программа должна будет ежедневно "доливать"
в готовую базу примерно по 1 млн. новых записей.
Также было предложено реализовать все это на платформе .NET.
Поскольку до этого я программировал в основном под Win32 на C++, то и писать стал
на С++. Но вскоре, испытав отвращение ко всем наворотам, введенным в VC++ для поддержки
.NET, я решил, что лучше, проще и элегантнее написать это на C#.
Но так как многих деталей C# я еще не знаю, есть некоторые сложности.
Самый неясный момент для меня сейчас: как грамотно организовать обработку исключений
(и запись их в журнал!) при работе с SQL server и при этом освободить ресурсы (connection)
в случае ошибки?
Указанная процедура будет вызываться многократно и не должна выпускать исключение вовне.
Вот фрагмент кода, но что-то подсказывает мне, что он еще далек от идеала
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
//
// Записать все записи из памяти в БД одной транзакцией!
//
// В случае успеха все записи добавляются в таблицу cdr_records,
// а имя файла добавляется в таблицу cdr_files (COMMIT)
//
// В случае неудачи - ничего не происходит и делается запись в журнал (ROLLBACK)
//
static void WriteRecordsToDB (
string shortFilename, // in: имя CDR-файла
List<CdrRecord> cdrRecordsList // in: массив записей, прочитанных из CDR-файла
)
{
try {
// вариант с using(...) из примера MSDN
using (SqlConnection connect = new SqlConnection (DBCONNECTION_STRING)) {
// установить соединение с SQL сервером - может бросить исключение!
connect.Open ();
SqlTransaction transaction = connect.BeginTransaction ("MyTransaction");
try {
SqlCommand cmd = connect.CreateCommand ();
cmd.Connection = connect;
cmd.Transaction = transaction;
cmd.CommandType = System.Data.CommandType.Text;
// записать все записи из массива в БД
for (int i = 0; i < cdrRecordsList.Count; ++i) {
CdrRecord rec = cdrRecordsList[ i ];
StringWriter strWriter = new StringWriter ();
strWriter.Write ("'{0}', '{1}', '{2}', '{3}', '{4}'",
rec.data_type, rec.field_a, rec.field_b, , rec.field_c, rec.field_d
);
cmd.CommandText = "INSERT INTO cdr_records " +
"(data_type, rec.field_a, rec.field_b, , rec.field_c, rec.field_d) " +
"VALUES (" + strWriter.ToString () + ")";
cmd.ExecuteNonQuery ();
}
// записать имя обработанного файла в БД
cmd.CommandText = "INSERT INTO cdr_files (fname) VALUES ('" + shortFilename + "')";
cmd.ExecuteNonQuery ();
// попытаться завершить транзакцию
transaction.Commit ();
}
catch (Exception ex) {
LogMessage ("WriteRecordsToDB(): " + shortFilename + " is not processed.", ex);
// попытать откатить транзакцию
try {
transaction.Rollback ();
}
catch (Exception ex2) {
LogMessage ("WriteRecordsToDB(): transaction.Rollback() failed.", ex2);
}
}
}
}
catch (Exception ex) {
// перехват connect.Open(), BeginTransaction()
LogMessage ("WriteRecordsToDB(): " + shortFilename + " is not processed.", ex);
}
}