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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Ошибка удаления строки, если есть идентичная удаляемой 
V
    Опции темы
ДобренькийПапаша
Дата 29.9.2009, 09:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 14.1.2006
Где: г.Москва

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



У меня есть таблица с четырьмя полями: 1)шифр (внешний ключ), 2)семестр, 3)сумма, 4)дата.
То есть ни одного первичного ключа нет.
Если вставить абсолютно идентичные записи, то ни одну из них нельзя удалить, при попытке удаления (удаляю из Management Studio) получаю сообщение:

Произошла ошибка при попытке удалить строку <номер удаляемой строки>.
Источник ошибки:Microsoft.VisualStudio.DataTools.
Сообщение об ошибке:Значения строки обновлены или удалены, либо не делают строку уникальной, либо они изменяют несколько строк (строк:<количество строк>).

Исправьте ошибки и попробуйте удалить снова бла-бла-бла-бла-бла-бла.

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

Но мне просто интересно, почему возникает такая ошибка? Что за механизм такой?

p.s. Я немного пояндексил, говорят, что, мол, это на стороне клиента. Однако, конкретно в этом случае, я в этом сильно сомневаюсь, и, ощущение, что ошибка возникает на стороне сервера. 


--------------------
Меня зовут Себастьян Парейра, торговец чёрным деревом.
PM MAIL   Вверх
Akina
Дата 29.9.2009, 09:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

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



Цитата(ДобренькийПапаша @  29.9.2009,  10:06 Найти цитируемый пост)
мне просто интересно, почему возникает такая ошибка?

Тебе же вполне вменяемо сообщают:
Цитата(ДобренькийПапаша @  29.9.2009,  10:06 Найти цитируемый пост)
либо они изменяют несколько строк 

Ты удаляешь одну запись, их две, СУБД не сможет решить, какая именно удаляется, Студия это понимает и посылает тебя нафиг. И она права.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Zloxa
Дата 29.9.2009, 09:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

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



Цитата(ДобренькийПапаша @  29.9.2009,  09:06 Найти цитируемый пост)

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

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


--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
ДобренькийПапаша
Дата 29.9.2009, 12:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 14.1.2006
Где: г.Москва

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



1)Почему не решу?
2)Вот скажем добавил первичный ключ, когда вставляется строка с уже существующим первичным ключом, то получаю сообщение от SqlServer, что нельзя вставить строку. Я хочу выдавать пользователю мной сформированное сообщение. Как это сделать лучше всего?
Сейчас я для этого использую хранимку с проверкой IsExists() и на стороне клиента делаю MessageBox.Show().


--------------------
Меня зовут Себастьян Парейра, торговец чёрным деревом.
PM MAIL   Вверх
Akina
Дата 29.9.2009, 12:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

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



Цитата(ДобренькийПапаша @  29.9.2009,  13:25 Найти цитируемый пост)
Почему не решу?

Потому что записей - две. Они абсолютно идентичны. Различить их невозможно.

Цитата(ДобренькийПапаша @  29.9.2009,  13:25 Найти цитируемый пост)
Сейчас я для этого использую хранимку с проверкой IsExists() и на стороне клиента делаю MessageBox.Show(). 

А просто анализ кода возврата, без всяких там IfExist - некошерно? слишком просто смотрится?


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Zloxa
Дата 29.9.2009, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

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



Цитата(ДобренькийПапаша @  29.9.2009,  12:25 Найти цитируемый пост)
1)Почему не решу?


Цитата(ДобренькийПапаша @  29.9.2009,  12:25 Найти цитируемый пост)

Сейчас я для этого использую хранимку с проверкой IsExists() и на стороне клиента делаю MessageBox.Show(). 

две сессии  одновременно пытаются вставить две одинаковые строки:

первая сессия проверила isExists, проверка выполнилась успешно
первая сессия добавила строку
вторая сессия проверила isExists, проверка выполнилась успешно
вторая сессия добавила строку
первая сессия фиксировалась
вторая сессия фиксировалась.

ты имеешь две строки.


Это сообщение отредактировал(а) Zloxa - 29.9.2009, 12:50


--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
ДобренькийПапаша
Дата 29.9.2009, 13:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 14.1.2006
Где: г.Москва

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



У меня если кто-то обращается к данным, то только он может изменять их. Все остальные блокируются.
К сожалению у меня тут через отдельно разработанный класс вызовы хранимок происходят и обрабатывать код ошибок не могу. Или не везде могу.


--------------------
Меня зовут Себастьян Парейра, торговец чёрным деревом.
PM MAIL   Вверх
Zloxa
Дата 29.9.2009, 14:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

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



Цитата(ДобренькийПапаша @  29.9.2009,  13:43 Найти цитируемый пост)
Все остальные блокируются.

Мне такой подход напоминает анекдот про чукчу, который купил камаз. Все бы, говорит, хорошо, только вот собаки быстро устают. ;)

В чем, собственно, заключается проблема, которая перед Вами стоит? Я чтото перестал понимать.


--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
ДобренькийПапаша
Дата 29.9.2009, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 14.1.2006
Где: г.Москва

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



Проблема такая.
Пример: Есть таблица с полями id (ключ, с автоматическим инкрементом), fullName (имя факультета), shortName(короткое имя факультета).
Есть форма на которой отображаются все факультеты. Есть кнопка "Добавить". Если человек добавляет, то надо проверить есть ли факультет с таким названием, и соответственно, либо добавить, либо сказать, что такой уже есть.
Есть кнопка "Update" вызывается другая форма, тут человек может изменить короткое название или длинное.
Тут просто так запускать IsExists() нельзя, потому-что если человек просто изменил короткое название, то IsExists() сработает и не даст ему это сделать.

Пока решил так:

Код

private void FacultyAdd_Click(object sender, EventArgs e)
        {
            AddUpdateFaculty curEx = new AddUpdateFaculty("AddButton", (short)CourseList.Items.Count);
            if (curEx.ShowDialog() == DialogResult.OK)
            {
                if (!IsExistFaculty(curEx.propFacFullName))
                {
                    ProcInvoke.ExecuteQuery("AddFaculty", QueryType.ExecuteNonQuery, CommandType.StoredProcedure,
                                            new ProcParams("@FacShortName", SqlDbType.VarChar, 50,
                                                           curEx.propFacShortName,
                                                           ParameterDirection.Input),
                                            new ProcParams("@FacFullName", SqlDbType.VarChar, 50, curEx.propFacFullName,
                                                           ParameterDirection.Input),
                                            new ProcParams("@countCourses", SqlDbType.SmallInt, 0, curEx.propGrade,
                                                           ParameterDirection.Input));
                    PreparationOnStart();
                }
                else
                {
                    MessageBox.Show("Факультет с таким названием уже существует!", "Ошибка", MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);
                }
            }
        }
 private void FacultyUpdate_Click(object sender, EventArgs e)
        {
            string facFullName = FacultyCathedralTree.SelectedNode.Text;
            string facShortName = null;

            using (SqlDataReader shortFacNameReader =
                (SqlDataReader)
                ProcInvoke.ExecuteQuery("GetFacShortNameByFullName", QueryType.ExecuteReader,
                                        CommandType.StoredProcedure,
                                        new ProcParams("@FacFullName", SqlDbType.VarChar, 50, facFullName,
                                                       ParameterDirection.Input)))
            {
               while (shortFacNameReader.Read())
                {
                    facShortName = shortFacNameReader["ShortName"].ToString();
                }
                shortFacNameReader.Close();   
            }

            AddUpdateFaculty curEx = new AddUpdateFaculty("UpdateButton", (short)CourseList.Items.Count,
                                                            facShortName, facFullName);

            if (curEx.ShowDialog() == DialogResult.OK)
            {
                if (facFullName == curEx.propFacFullName)
                {
                    FacultyUpdateProc(curEx);
                }
                else
                {
                    if(!IsExistFaculty(curEx.propFacFullName))
                    {
                        FacultyUpdateProc(curEx);
                    }
                    else
                    {
                        MessageBox.Show("Факультет с таким названием уже существует!", "Ошибка", MessageBoxButtons.OK,
                                        MessageBoxIcon.Error);
                    }
                }
                
            }
            
        }


То есть при апдэйте я проверяю изменял ли он полное название, если нет, то сразу можно сделать апдэйт, а если изменял,
то запустить сначала IsExists(), и если такое присутствует, то отказать.


А что, вроде нормально работает, может немножко вычурно, но всё вроде довольно логично.
То есть пока, как-бы проблема решена.

Вопрос: А что плохого, в том, чтобы запрещать клиентам одновременно вносить изменения в одно и то же место?
(Я уровень блокировки транзакции просто установлю).
Какие-то явные минусы?


--------------------
Меня зовут Себастьян Парейра, торговец чёрным деревом.
PM MAIL   Вверх
Akina
Дата 29.9.2009, 15:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

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



Цитата(ДобренькийПапаша @  29.9.2009,  15:59 Найти цитируемый пост)
если изменял, то запустить сначала IsExists(), и если такое присутствует, то отказать.

Это почему? Может, он намерен изменить именно короткое название другой записи, и её длинное название он указывает. Правда это так, к слову, и допускаться не должно, ибо не та запись.
Но вообще вся твоя проблема - именно оттого, что ты не желаешь использовать для идентификации ключевое поле ID. Именно оно должно отвечать за привязку наименований к другим таблицам. И дублирование тут вовсе не помеха. Мало ли что названия совпадают? факультеты-то разные... А для регистрации изменения наименований следует предусмотреть журнал. Он мгновенно покажет виновного в бардаке. После чего к нему применяются меры отнюдь не программного характера. Тем более что изменение названия факультета - вещь весьма редкая.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Zloxa
Дата 30.9.2009, 09:44 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

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



Цитата(ДобренькийПапаша @  29.9.2009,  14:59 Найти цитируемый пост)
(Я уровень блокировки транзакции просто установлю).

Что такое уровень блокировки транзакции?

Видимо Вы имете в виду уровень изоляции транзакции.
Для того чтобы обеспечить уникальность поля, вам придется для всех модифицирующих сессий выставлять уровень изоляции Serializable и обязательно проверять IsExists в той же транзакции, в которой проводите модификацию.  В этом случае, если две сессии попытаются таки установить одинаковое значение, одна из них отвалится по дедлоку/*т.е. анализировать ответ сервера таки все равно придется*/. В виду того что поле FullName у вас не индексировано, добавившая или изменившая запись сессия, до завершения транзакции блокирует все сессии, которые пытаются отобратья по FullName, даже если отбор идет по другому значению. Когда мы выносим управление транзакциями на клиента, надо помнить, что клиент может вдруг неожиданно внештатно отвалиться. В этом случае серверу придется некоторое время держать открытыми его транзакции, блокируя при том других пользователей.

Как бы не самый ровный путь, не правда ли?
А все для чего? Для того чтобы вынести контроль целостности данных на сторону приложения.
А все от чего? От того, что Вы, по каким то не понятным мне соображениям избегаете анализа ответа сервера.

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

Задача которая перед вами стоит - тривиальна. Именно от того, мне вспоминается анекдот про чукчу. 
Решение сводится к наложению ограничения уникальности на FullName.
И на клиенте не нужны ни какие IsExists. Достаточно лишь выполнить операцию и проверить ответ сервера.
И на клиенте не нужны ни какие какие управления транзакциями.
И в результате вы получаете на много более масштабируемое решение, которое будет на несколько порядков меньше тупить, в случае прироста пользовательской нагрузки.

Это сообщение отредактировал(а) Zloxa - 30.9.2009, 13:21


--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
ДобренькийПапаша
Дата 30.9.2009, 15:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 14.1.2006
Где: г.Москва

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



Хорошо. Я посмотрю, смогу ли я обработать в catch там где надо код ответа сервера. Просто тут по коду есть проблемы...


--------------------
Меня зовут Себастьян Парейра, торговец чёрным деревом.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "MS SQL"
Akina

Akina

Запрещается!

Публиковать ссылки и обсуждать взлом чего бы то ни было.

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы составления неспецифических запросов рассматриваются здесь
  • Используйте теги [code=sql][/code] для подсветки кода. Используйтe чекбокс "транслит" (возле кнопок кодов) если у Вас нет русских шрифтов.

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

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


 




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


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

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