Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 12.11.05 14:46
Оценка:
Привет всем! Тема типизированный датасет и транзакция несовместимы друг с другом и вот почему. Пусть есть одна таблица, в котрой мы модифицируем 1,2 и 3 строку. далее пишем код сохранения
SqlTransaction tran = DbConnection.BeginTransaction();
try
{
// Включеам команды адаптера в транзакцию
mdm_ColorTableAdapter.Settransaction(tran);
this.mdm_ColorTableAdapter.Update(tableColor);
tran.Commit();
}
catch (Exception err)
{
tran.Rollback();
MessageBox.Show(err.Message);
}

Теперь, внимание! Если в третей строке сервер даст ошибку (нам сейчас не важно почему) и произойдёт откат транзакции, то у первых двух строк Adapter выставит DataRowState.Unchanged!!! И всё!!! Хоть убейся значения 1 и 2 строки уже не передадутся никогда!!! Если, теперь исправив значения в 3 строке на правильно, запустить сохранение, то получим: 3 передалось, а 1 и 2 нет!!! Так как же нам быть?
С уважением, Михаил






данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: pavel_turbin  
Дата: 12.11.05 15:06
Оценка:
Здравствуйте, mikl bob1, Вы писали:


MB> Теперь, внимание! Если в третей строке сервер даст ошибку (нам сейчас не важно почему) и произойдёт откат транзакции, то у первых двух строк Adapter выставит DataRowState.Unchanged!!! И всё!!! Хоть убейся значения 1 и 2 строки уже не передадутся никогда!!! Если, теперь исправив значения в 3 строке на правильно, запустить сохранение, то получим: 3 передалось, а 1 и 2 нет!!! Так как же нам быть?


модифицировать и записывать по одной записи.
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 12.11.05 15:35
Оценка:
Привет всем! Пример тестовый! В жизни это накладная = шапка+ детальная часть с большим количеством строк! Уж тут не по строчкам! Потом если так устроен "дот нет" то кому он нужен?


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 12.11.05 16:00
Оценка:
Можно попробовать установить своиство
DataAdapter.AcceptChangesDuringUpdate = false;
тогда он не скинет DataRowState, но при повторном выполнении облом — Concurrency violation дескать ждал от апдейта 1 строки что rowcount =1 а получил 0. Они считаетют дескать другой пользователь уже модифицирвал! Дурдом какой то!


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 12.11.05 17:43
Оценка:
Commit просто в "finally" нужно ложить, а не в "try".

SqlTransaction tran = DbConnection.BeginTransaction();
mdm_ColorTableAdapter.Settransaction(tran);
try
{
// Включеам команды адаптера в транзакцию

this.mdm_ColorTableAdapter.Update(tableColor);

}
catch (Exception err)
{
tran.Rollback();
MessageBox.Show(err.Message);
}
finally
{
tran.Commit();
}
Real programmers don't comment their code. If it was hard to write, it should be hard to understand.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 12.11.05 20:08
Оценка:
Hotja gonju, kazhetsja...

No vsjo ravno u tebja ne to chto-to... Ne dolzhno bit' takogo.

Real programmers don't comment their code. If it was hard to write, it should be hard to understand.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 12.11.05 20:32
Оценка:
Ставить "AcceptChangesDuringUpdate = false" это как раз правильно, только потом, нужно делать руками "AcceptChanges" обязательно.

Real programmers don't comment their code. If it was hard to write, it should be hard to understand.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 13.11.05 07:57
Оценка:
Вы все локально делаете? Не через ремоутинг или веб-сервисы?
Если так, то нужно передавать адаптеру таблицу (или датасет) содержащую только изменения, т.е. GetChanges.
Потом, если все ок, на таблицу-источник и таблицу-изменений выполнить Merge.




данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 13.11.05 07:58
Оценка:
Датасет не подерживает транзакции. Хотя.. с новой моделью транзакций в .net 2.0 можно попробовать что-нибудь наваять.



данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 13.11.05 11:20
Оценка:
Спасибо за сочуствие! Тигру special thank! Разор идёт о клиент ( Windows App) серверной (MS SQL 2000) системе. Проблема не куда "ложить" commit, а в том как в простую солдатскую душу DataAdaptera заронить подозрение, что не дождавшись конца всей транзакции нельзя скидывать DataRowState! Ну просто очевидно что должна быть симметрия- у транзакции 2 возможности Commit and RollBack, точно так и должно быть у адаптера, иначе кому он нужен!!!


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 17.11.05 10:18
Оценка:
2 BlackTigerAP.
Уважаемый Тигр. Блок finally исполняется ВСЕГДА. Если использовать Ваш совет, то при выбросе исключения отработает и tran.Rollback( ) и tran.Commit( ). Как-то не очень красиво получается.
Глубоко убежден, что фиксировать транзакцию надо в блоке try. А вот в finally надо помещать освобождение разнообразных ресурсов.
Данный подход, в общем то, идиоматический.
Всего наилучшего.



данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 17.11.05 11:34
Оценка:
Тигр погяричился! Однако рецепт найден
adapter.AcceptChangesDuringUpdate = false;
то есть код выглядит так

adapter.AcceptChangesDuringUpdate = false;
using (SqlTransaction tran = DBConnection.BeginTransaction())
{
try
{
Adapter.Update(ArtcTable);
tran.Commit();
ArtcTable.AcceptChanges();
}
catch (System.Data.SqlClient.SqlException err)
{
tran.Rollback();
}
}









данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 17.11.05 12:31
Оценка:
Дык, я ж давно написал, что херню спорол. Почти сразу же после моего поста.

Real programmers don't comment their code. If it was hard to write, it should be hard to understand.


данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 23.11.05 15:40
Оценка:
Вы на добавленных строках пробовали?
Потому-что на добавляемые строки AcceptChanges вызывается дважды — первыйраз добавления строки в БД и до обратного чтения той же строки, а второй раз после обратного чтения в строку, но уже в зависимости от AcceptChangesDuringUpdate.



данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Я в шоке - данные нельзя сохранять в транзакции!
От: Аноним  
Дата: 10.02.06 09:37
Оценка:
Привет!
А можно по подробнее про метод TableAdapter.Settransaction(tran);

Как я понимаю, DataAdapter в TableAdapter является private, и вы до него не доберётесь, без расширения TypedDataSetGenerator как сказал Alex Leshkin в посте http://www.gotdotnet.ru/Forums/Data/277286.aspx.

Единственное, надо разобраться как модифицировать TypedDataSetGenerator, что-бы он генерировал Adapter с public.





данное сообщение получено с www.gotdotnet.ru
ссылка на оригинальное сообщение
Re: Я в шоке - данные нельзя сохранять в транзакции!
От: Alex Leshkin  
Дата: 14.02.06 11:36
Оценка:
Здравствуйте, black, Вы писали:

B>Привет!

B>А можно по подробнее про метод TableAdapter.Settransaction(tran);

B>Как я понимаю, DataAdapter в TableAdapter является private, и вы до него не доберётесь, без расширения TypedDataSetGenerator как сказал Alex Leshkin в посте http://www.gotdotnet.ru/Forums/Data/277286.aspx.


B>Единственное, надо разобраться как модифицировать TypedDataSetGenerator, что-бы он генерировал Adapter с public.

Примерно так:

//Генерим адаптеры
// schema - схема датасета
private void createAdapters(DbProviderFactory providerFactory, string schema) {
    CodeCompileUnit compileUnit = new CodeCompileUnit();
    compileUnit.ReferencedAssemblies.Add("System.dll");
    compileUnit.ReferencedAssemblies.Add("System.Data.dll");
    compileUnit.ReferencedAssemblies.Add("System.Xml.dll");
    CodeNamespace codeNamespace = new CodeNamespace("Tralyalya.Data.Access.Adapters");
    CSharpCodeProvider codeProvider = new CSharpCodeProvider();
    System.Data.Design.TypedDataSetGenerator.Generate(schema,
                                                compileUnit,
                                                codeNamespace,
                                                codeProvider,
                                                providerFactory);
    List<string> propNames = new List<string>();
    propNames.Add("Adapter");
    propNames.Add("Connection");
    propNames.Add("CommandCollection");
    propNames.Add("ClearBeforeFill");
    //Поправим адаптеры перед генерацией
    PropertiesToPublic(propNames, compileUnit.Namespaces[0]);
    CodeGeneratorOptions codeGeneratorOptions = new CodeGeneratorOptions();
    StringWriter writer = new StringWriter();
    writer.WriteLine(@"#pragma warning disable 1591");
    codeProvider.GenerateCodeFromCompileUnit(compileUnit, writer, codeGeneratorOptions);
    writer.WriteLine(@"#pragma warning restore 1591");

    File.WriteAllText("TableAdapters.Generated.cs", writer.ToString());
}

//А здесь правим адаптеры как нам надо перед генерацией в код
//propNames - это те проперти, которым надо public сделать
private void PropertiesToPublic(List<string> propNames, CodeNamespace ns) {
    CodeTypeDeclaration[] types = new CodeTypeDeclaration[ns.Types.Count];
    ns.Types.CopyTo(types, 0);

    foreach (CodeTypeDeclaration type in types) {
        CodeTypeMember[] members = new CodeTypeMember[type.Members.Count];
        type.Members.CopyTo(members, 0);

        foreach (CodeTypeMember member in members) {
            if (member is CodeMemberField) {
                CodeMemberField field = (CodeMemberField)member;
                if (field.Name.ToUpper() == "_CONNECTION") {
                    field.Type = new CodeTypeReference(typeof(DbConnection));
                }
                if (field.Name.ToUpper() == "_ADAPTER") {
                    field.Type = new CodeTypeReference(typeof(DbDataAdapter));
                }
                if (field.Name.ToUpper() == "_COMMANDCOLLECTION") {
                    field.Type = new CodeTypeReference(typeof(DbCommand[]));
                }
            } else if (member is CodeMemberProperty) {
                CodeMemberProperty property = (CodeMemberProperty)member;
                //Вот именно здесь мы public и пропишем
                if (propNames.Contains(property.Name)) {
                    //Override нужен был исключительно в моем случае
                    //так что его можно убрать
                    property.Attributes = MemberAttributes.Public | MemberAttributes.Override;
                }
                //Исправление приведения типа для проперти Connection
                //Это делать не обязательно, но если есть базовый класс для адаптеров,
                //может оказаться полезным.
                if (property.Name.ToUpper() == "CONNECTION") {
                    property.Type = new CodeTypeReference(typeof(DbConnection));
                    CodeIterationStatement codeIterationStatement = (CodeIterationStatement)property.SetStatements[4];
                    CodeConditionStatement codeConditionStatement = (CodeConditionStatement)codeIterationStatement.Statements[0];
                    CodeAssignStatement codeAssignStatement = (CodeAssignStatement)codeConditionStatement.TrueStatements[0];
                    CodePropertyReferenceExpression codePropertyReferenceExpression = (CodePropertyReferenceExpression)codeAssignStatement.Left;
                    CodeCastExpression codeCastExpression = (CodeCastExpression)codePropertyReferenceExpression.TargetObject;
                    codeCastExpression.TargetType.BaseType = "System.Data.Common.DbCommand";

                }
                if (property.Name.ToUpper() == "ADAPTER") {
                    property.Type = new CodeTypeReference(typeof(DbDataAdapter));
                }
                if (property.Name.ToUpper() == "COMMANDCOLLECTION") {
                    property.Type = new CodeTypeReference(typeof(DbCommand[]));
                }
            }
        }
    }
}


ну а потом можно делать partial class для адаптера, либо использовать базовый класс,
где реализовать SetTransaction, что мне кажется более удобным.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.