Страница: 1 |
Страница: 1 |
Вопрос: .Net одна транзакция для всех адаптеров или таблиц
Добавлено: 17.03.07 15:54
Автор вопроса: Neco | Web-сайт:
Вопрос из двух частей.
Первое - удаляю данные из DataTable'ов. К примеру пять штук, нажимаю кнопку и имею код по типу:
tbl1.Rows[1].Delete();
tbl2.Rows[154].Delete();
и предположим, что третья строка не смогла удалится - хз почему - вылетел эксепшн, мы показали ошибку юзеру, всё в порядке, но первые две строки удалились, а третья нет - логическая целостность нарушена.
Как объеденить удаление одним действием, чтобы "либо всё, либо ничего"?
Данные между собой завязаны только логически - у меня, например, в одной таблице находятся слова на разных языках. Уникальность по двум полям - ID и LANG_ID. Если удалять, то данные на всех языках. Напрямую в базе, я бы сделал delete from man.dict where id=:id и не парился бы, а в таблицах приходится удалять построчно - и тут можно нарваться.
Я видел какие-то методы RejectChanges() у строк и таблиц, но они отменяют все изменения, а не только вот эти три последних. Надо как-то поставить отметку вначале этих действий, но как?
Второе - вносим изменения собственно в базу данных:
private void Apply()
{
try
{
using (OracleConnection conn = new OracleConnection(pub.session.ConnectionString))
{
//OracleConnection conn = new OracleConnection(pub.session.ConnectionString);
this.oRDER_RUN_TIME_TYPETableAdapter.Connection = conn;
this.oRDER_SQLTableAdapter.Connection = conn;
this.dICTTableAdapter.Connection = conn;
this.oRDER_PARAM_TYPETableAdapter.Connection = conn;
this.oRDER_RETURN_TYPETableAdapter.Connection = conn;
this.dICTTableAdapter.Update(this.xeDataSet.DICT);
this.oRDER_PARAM_TYPETableAdapter.Update(this.xeDataSet.ORDER_PARAM_TYPE);
this.oRDER_RETURN_TYPETableAdapter.Update(this.xeDataSet.ORDER_RETURN_TYPE);
this.oRDER_RUN_TIME_TYPETableAdapter.Update(this.xeDataSet.ORDER_RUN_TIME_TYPE);
this.oRDER_SQLTableAdapter.Update(this.xeDataSet.ORDER_SQL);
}
}
catch (Exception ex)
{
throw ex;
}
}
И опять та же фигня - если что-то помешает посередине пути оновить данные, то мы получим нарушение целостности уже не в памяти, а в самой базе. Адаптеры можно объеденить одним коннектом, но не получается объеденить одной транзакцией. (((
Как быть?
Ответы
Всего ответов: 8
Номер ответа: 1
Автор ответа:
EROS
Вопросов: 58
Ответов: 4255
Профиль | | #1
Добавлено: 17.03.07 23:08
new SqlConnection(connectionString))
{
SqlCommand command = connection.CreateCommand();
SqlTransaction transaction = null;
try
{
// BeginTransaction() Requires Open Connection
connection.Open();
transaction = connection.BeginTransaction();
// Assign Transaction to Command
command.Transaction = transaction;
// Execute 1st Command
command.CommandText = "Insert ...";
command.ExecuteNonQuery();
// Execute 2nd Command
command.CommandText = "Update...";
command.ExecuteNonQuery();
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
finally
{
connection.Close();
}
}
Номер ответа: 2
Автор ответа:
EROS
Вопросов: 58
Ответов: 4255
Профиль | | #2
Добавлено: 17.03.07 23:10
transaction.Commit '// подверждаем транзакцию;
transaction.Rollback() '// откатываемся
Номер ответа: 3
Автор ответа:
Neco
ICQ: 247906854
Вопросов: 133
Ответов: 882
Web-сайт:
Профиль | | #3
Добавлено: 17.03.07 23:14
пасиб конечно )
но я как бы про это знал... ))
мне надо:
1. Транзакцию в памяти. Чтобы таблицы содержали единовременную информацию.
2. Выполнить Update группой адаптеров одной транзакцией. А у адаптера нет свойства Transaction, как у команды.
Номер ответа: 4
Автор ответа:
Neco
ICQ: 247906854
Вопросов: 133
Ответов: 882
Web-сайт:
Профиль | | #4
Добавлено: 17.03.07 23:22
и кстати, если позволишь заметить, не совсем правильный кусочек кода ты мне дал. )))
если коннект не пройдёт по причине неправильного пароля, к примеру, то этот блок вылетит с ошибкой Object instance not set - про транзакцию, которую он попытается откатить при том, что переменная ещё не будет заведена.
правильнее имхо делать так:
{
try
{
using (OracleConnection conn = new OracleConnection(pub.session.ConnectionString))
{
conn.Open();
using (OracleTransaction tran = conn.BeginTransaction())
{
using (OracleCommand cmd = new OracleCommand("", tran.Connection))
{
cmd.Transaction = tran;
try
{
// any code
tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();
throw ex;
}
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
Номер ответа: 5
Автор ответа:
Павел
Администратор
ICQ: 326066673
Вопросов: 368
Ответов: 5968
Web-сайт:
Профиль | | #5
Добавлено: 19.03.07 18:54
Вообще DataAdapter может быть построен на основе DataCommand (в
конструктор ее передать, или в какое-нть свойство загнать)...
А поьзоваться визуальными компонентами для работы с данными - ИМХО
зло. Для чего-то сложнее Helo World лучше решения похитрее писать.
Номер ответа: 6
Автор ответа:
Neco
ICQ: 247906854
Вопросов: 133
Ответов: 882
Web-сайт:
Профиль | | #6
Добавлено: 19.03.07 19:11
по ситуации. сейчас вот столкнулся с тем, что надо бы визуально - чтобы побыстрее писАлось. но если б не такие вот тонкости...
а насчёт DataCommand большое спасибо - попробую
наверно должно сработать
Номер ответа: 7
Автор ответа:
Neco
ICQ: 247906854
Вопросов: 133
Ответов: 882
Web-сайт:
Профиль | | #7
Добавлено: 07.04.07 17:18
Народ!
Вопрос всё ещё открыт - идей ни у кого нет?
Вариант с созданием через команду в кострукторе не получился. Типизированый адаптер вообще не унаследован от простого адаптера - он просто внутри его как переменную содержит.
Сейчас решаю использовать вариант с тем, чтобы когда уже всё будет готово, объявить свойство CommandCollection публично ручками в подготовленном дизайнером коде. Тока при поправках датасета всё слетать будет...
Блевануть тянет, но не могу больше ничего придумать...
Номер ответа: 8
Автор ответа:
Павел
Администратор
ICQ: 326066673
Вопросов: 368
Ответов: 5968
Web-сайт:
Профиль | | #8
Добавлено: 07.04.07 18:24
Я бы рекомендовал переписать код с использованием нормальной архитектуры, и навсегда забыть про типизированные Dataset'ы, Table Adapter'ы и прочие поделки.