Модераторы: gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Удаление вновь созданный записи, Удалить только что созданную запись 
:(
    Опции темы
albert21
  Дата 8.3.2006, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 166
Регистрация: 10.1.2006

Репутация: нет
Всего: нет



Проблема: В одной из таблиц базы данных создаётся новая запись
Код

        public void InsDisk(DataSetDiskoteka dts, string name, string image, string description, string kategoria, string genre, string type)
        {
            DataRow dr = dts.Tables["Disk"].NewRow();
            dr["Название"] = name;
            dr["Изображение"] = image;
            dr["Описание"] = description;
            dr["Категория"] = kategoria;
            dr["Жанр"] = genre;
            dr["Тип_носителя"] = type;
            dts.Tables["Disk"].Rows.Add(dr);
        }
...
AdapterDisk.Update(dts, "Disk");


Сразу после появления этой записи в гриде, выделяем её и нажимаем кнопку "Удалить":

Код

             DataView dataView = new DataView(dts.Tables["Disk"]);
             foreach (DataGridViewRow r in dataGridDisk.SelectedRows)
             {
                 dataView.Delete(r.Index);

             }
...
AdapterDisk.Update(dts, "Disk");


И вот тут может появиться ошибка! Подчёркиваю МОЖЕТ. Ошибка появляется на последней строке приведённого кода: AdapterDisk.Update(dts, "Disk"); Ругается следующими словами: Concurrency violation: the DeleteCommand affected 0 of the expected 1 records.

Подскажите пожалуйста как решить
--------------------
http://www.certifications.ru/publicresults.php?tu_id=45939
PM MAIL   Вверх
mr.DUDA
Дата 8.3.2006, 17:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 8
Всего: 232



Видимо, адаптер толком не понимает что ему делать с записью, которую добавили а потом удалили - добавлять и удалять из БД ? smile


--------------------
user posted image
PM MAIL WWW   Вверх
albert21
Дата 8.3.2006, 19:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 166
Регистрация: 10.1.2006

Репутация: нет
Всего: нет



В пошаговом режиме после нажатия кнопки "ДОБАВИТЬ" в базе данных действительно появляется запись. Возможно запись в ДатаСет имеет некое специальное состоянние, когда факт обновления не подтверждён! Но это только мои догадки! Есть метод который бы железно подтвердил ранее внесённые изменения в набор данных?
--------------------
http://www.certifications.ru/publicresults.php?tu_id=45939
PM MAIL   Вверх
-ser-
Дата 9.3.2006, 05:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 1.2.2005

Репутация: 4
Всего: 13



стоп, стоп, стоп.
все не совсем так. не четко описаны намерения, в каком состоянии наши записи, когда мы что-то дальше пытаемся с ними делать.

Цитата

Сразу после появления этой записи в гриде, выделяем её и нажимаем кнопку "Удалить":

здесь очень важно на каком этапе мы хотим удалить запись?
Цитата

Возможно запись в ДатаСет имеет некое специальное состоянние, когда факт обновления не подтверждён!

именно так!

существует несколько промежуточных версий и состояний записи, а именно аж
4 разных версии : current, original, default, proposed.
и 5 разный состояний: added, deleted, detached, modified, unchanged.
и механизм ее удаления зависит от того, в какой версии и в каком состоянии она находится в данный момент. и если мы ее видим в БД или в гриде, после того же добавления, это еще совсем ни о чем не говорит.

существует как минимум 3 основных табличных метода:
Код

AcceptChanges()    
RejectChanges()    
GetChanges()

и 8 основных методов манипуляций с записью:
Код

Add()    
InsertAt()
RemoveAt()    
AcceptChanges()
RejectChanges()
BeginEdit()
CancelEdit()
EndEdit()

использование которых влияет как на версию, так и на состояние записи(сей).

не буду приводить сюда подробный механизм работы всего вышеописанного. это заслуживает отдельной темы.
да дело даже и не в этом. в мире много всего более интересного, если конечно у нас не банковское приложение, с четким механизом отката транзакций в зависимости от ситуаций.

вернемся к нашей задаче.
для упрощения, отложим в сторону все, о чем я писал выше. договоримся, что любые изменения мы сразу же записываем в базу. неэффективно, но ошибки исключены.

1. правильнее Adapter.Update делать не на весь ДатаСет, а только на измененные записи. UpdateDataSet(...)

2. после этого, либо делаем dataSet.AcceptChanges(), либо, для чистоты эксперимента, возьмем и перезальем наш ДатаСет, предварительно его очистив dataSet.Clear();

тоже самое с удалением. проще некуда.

З.Ы. все это относится к ADO.NET, в ADO.NET 2.0 кое-что изменилось, но концепция та же. Что появилось нового, например, можно обойтись вообще без ДатаСета. ДатаТейбл уже стала независимой от ДатаСета и имеет колоссальную функциональность.


Это сообщение отредактировал(а) -ser- - 9.3.2006, 08:25


--------------------
"Тонкая, однако, работа." 
PM MAIL ICQ   Вверх
albert21
Дата 9.3.2006, 12:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 166
Регистрация: 10.1.2006

Репутация: нет
Всего: нет



Написал так:
Код

        public void DelDisk(DataGridView dataGridDisk, DataSetDiskoteka dts, System.Data.OleDb.OleDbDataAdapter adapter)
        {
            foreach (DataGridViewRow r in dataGridDisk.SelectedRows)
            {
                DataRow sRow = dataView[r.Index].Row;
                sRow.Delete();
                sRow.AcceptChanges(); //По идее удаление должно подтвердиться

            }
            if (!dts.HasChanges(DataRowState.Added | DataRowState.Modified | DataRowState.Deleted))
            {
                //MessageBox.Show("Hasn't been changed:" + DataRowState.Added + "  " + DataRowState.Modified);
                return;
            }
            DataSet xDataSet = new DataSet();
            xDataSet = dts.GetChanges(DataRowState.Added | DataRowState.Modified | DataRowState.Deleted);
            adapter.Update(xDataSet, "Disk");
        }


1) В таком варианте удаления не происходит вообще! Нет из ДАТАГРИД всё удаляется, а из базы НЕТ! Виноват в этом sRow.AcceptChanges(); Этот метод даже по названию должен потверждать удаление, он же по факту его отменяет. Чего-то я не пойму!!! smile

2) Без sRow.AcceptChanges(); Изменений никаких, та жа ошибка. Ставил dts.AcceptChanges();, xDataSet.AcceptChanges(); до обновления adapter.Update(xDataSet, "Disk");, результат: из ДАТАГРИД всё удаляется, а из базы НЕТ!

Может я чего-то не догоняю, объясните плиз!!!
--------------------
http://www.certifications.ru/publicresults.php?tu_id=45939
PM MAIL   Вверх
-ser-
Дата 10.3.2006, 07:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 1.2.2005

Репутация: 4
Всего: 13



все правильно, смотри что происходит, xхх.AcceptChanges() у тебя сбрасывает все флаги изменений, и, соответственно, dts.GetChanges(...) не зафиксирует никаких изменений.
пока не разберешься с версиями и состояниями, просто не используй Accept/RejectChanges. adaptor.Update() cам вызовет AcceptChanges().
Код

{
   foreach (DataGridViewRow r in dataGridDisk.SelectedRows)
               dataView[r.Index].Row.Delete();

//метод с GetChanges и adaptor.Update()
}
//перезалей датасет: adaptor.Fill( dts, "Disk" ). Еще, если у тебя используется только одна таблица, вообще можно не использовать второй параметр в Fill/Update.



--------------------
"Тонкая, однако, работа." 
PM MAIL ICQ   Вверх
albert21
Дата 10.3.2006, 15:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 166
Регистрация: 10.1.2006

Репутация: нет
Всего: нет



Всё равно та жа ошибка на Update(). И потом перезалить датасет на мой взгляд не самое лучшая идея с точки зрения производительности. Может хорошая книжка (на русском) электронная по C# + ADO.NET у кого нибудь есть?
--------------------
http://www.certifications.ru/publicresults.php?tu_id=45939
PM MAIL   Вверх
-ser-
Дата 12.3.2006, 08:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 1.2.2005

Репутация: 4
Всего: 13



на этом форуме специальный раздел посвящен этому, где тонны литературы на любой вкус, уж не ленитесь посмотреть. можешь посмотреть вот это Альманах, том 1
если честно, сам так и не читал, почти всегда хватает MSDN.

по твоему примеру, попробуй адаптер и основной датасет сделать глобальными.


--------------------
"Тонкая, однако, работа." 
PM MAIL ICQ   Вверх
albert21
Дата 12.3.2006, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 166
Регистрация: 10.1.2006

Репутация: нет
Всего: нет



Раздел есть конечно, но там не указано на каком языке книга! smile
--------------------
http://www.certifications.ru/publicresults.php?tu_id=45939
PM MAIL   Вверх
albert21
Дата 12.3.2006, 13:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 166
Регистрация: 10.1.2006

Репутация: нет
Всего: нет



Проблема заключается в том, что при добавлении новой записи в DataSet эта запись получает значение автоинкремента от DataSet, которое формируется из значения последней записи прочитанной из базы данных увеличенного на единицу. В самой же базе данных значение автоинкремента может быть совершенно другим!!!.

Для того чтобы избавиться от ошибки необходимо повесить обработчик на Adapter:
Код

        private void AdapterDisk_RowUpdating(object sender, System.Data.OleDb.OleDbRowUpdatingEventArgs e)
        {
            int newID = 0;
            .... получаем значение автоинкремента из БД ....

            if ((e.StatementType == StatementType.Insert) || (e.StatementType == StatementType.Delete)) newID = ...присваиваем полученное значение...
            dts.Tables["Disk"].Columns["ID"].AutoIncrementSeed = newID;
            dts.Tables["Disk"].Columns["ID"].AutoIncrementStep = 1;
        }


Теперь вопрос: Как получить значение автоинкремента из БД MS Access?????
ДЛя MS SQL прокатит так вроде:
Код

    System.Data.OleDb.OleDbCommand idCMD = new System.Data.OleDb.OleDbCommand("SELECT @@IDENTITY", oleDbConnection);
            if ((e.StatementType == StatementType.Insert) || (e.StatementType == StatementType.Delete)) newID = Convert.ToInt32(idCMD.ExecuteScalar());

Добавлено @ 13:59
Чуть не забыл!!! Добрый совет: все украшения, типа "НАДО СКРЫТЬ НЕ НУЖНЫЕ ДЛЯ ПОЛЬЗОВАТЕЛЯ ПОЛЯ" делайте в самую последнюю очередь smile
--------------------
http://www.certifications.ru/publicresults.php?tu_id=45939
PM MAIL   Вверх
arilou
Дата 14.3.2006, 01:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Великий МунаБудвин
****


Профиль
Группа: Экс. модератор
Сообщений: 2646
Регистрация: 15.7.2004
Где: город-герой Минск

Репутация: 4
Всего: 61



Цитата(albert21 @ 12.3.2006, 13:56 Найти цитируемый пост)
Как получить значение автоинкремента из БД MS Access?????

SELECT @@IDENTITY для Аксеса не прокатывает, поэтому надо делать (другого способа не знаю) SELECT MAX(FieldID) FROM Table.


--------------------
user posted imageuser posted image
PM WWW ICQ   Вверх
albert21
Дата 14.3.2006, 19:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 166
Регистрация: 10.1.2006

Репутация: нет
Всего: нет



Цитата

SELECT @@IDENTITY для Аксеса не прокатывает, поэтому надо делать (другого способа не знаю) SELECT MAX(FieldID) FROM Table


Это тоже не пойдёт, так как записи в БД могут удаляться, а счётчик БД при этом не уменьшается.
Я решил проблему так: убираем счётчик вообще, делаем поле ID просто целочисленным, а при запуске приложения пишем
Код

            dts.Tables["Disk"].Columns["ID"].AutoIncrement = true;
            dts.Tables["Disk"].Columns["ID"].AutoIncrementSeed =Convert.ToInt32( dts.Tables["Disk"].Select(string.Empty, "ID desc" )[0]["ID"])+1;
            dts.Tables["Disk"].Columns["ID"].AutoIncrementStep = 1;


Если кто более удачное решение нароет, скиньте плиз!
--------------------
http://www.certifications.ru/publicresults.php?tu_id=45939
PM MAIL   Вверх
arilou
Дата 14.3.2006, 19:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Великий МунаБудвин
****


Профиль
Группа: Экс. модератор
Сообщений: 2646
Регистрация: 15.7.2004
Где: город-герой Минск

Репутация: 4
Всего: 61



Цитата(albert21 @ 14.3.2006, 19:24 Найти цитируемый пост)
Это тоже не пойдёт, так как записи в БД могут удаляться, а счётчик БД при этом не уменьшается.

Счетчик и не должен уменьшаться. Он будет все время увеличиваться. Поэтому MAX() как раз наоборот, прокатит.


--------------------
user posted imageuser posted image
PM WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
stab
mr.DUDA
Exception

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, stab, mr.DUDA, Exception.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Базы данных под .NET | Следующая тема »


 




[ Время генерации скрипта: 0.0523 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.