Форум программистов, компьютерный форум, киберфорум
C#: Базы данных
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/21: Рейтинг темы: голосов - 21, средняя оценка - 4.71
12 / 12 / 5
Регистрация: 06.03.2012
Сообщений: 182
SQLite

Добавление новой строки в DataTable и первичный ключ

28.03.2015, 09:43. Показов 4415. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
В SQLite при указании первичного ключа у таблице типа INTEGER, тот автоматически становиться автоинкрементируемым, что очень удобно - не нужно беспокоится о создании уникальных значений при добавлении записи.
Через SQLiteDataAdapter наполнил DataTable строками из этой таблицы (метод Fill).
Теперь нужно добавить новую запись в таблицу БД через добавление новой строки в DataTable и вызова метода Update у адаптера.
При добавлении новой строки я не указываю поле с первичным ключом, СУБД его сама создаст обеспечив последовательность и уникальность. Все так и происходит, Update добавляет новую запись в БД.
Тут же возникает проблема. DataTable не вкурсе, что и как там с этим полем и в итоге он содержит две строки - одну без Id созданную мной, а вторую с Id сгенерированную СУБД. При попытке добавить еще одну строку по томуже алгоритму (без указания Id) он говорит, что добавление невозможно т.к. такой Id уже существует (пустое значение). В попытках удалить сразу после добавления строку без Id, при следующем обновлении адаптер выполнит запрос DELETE в СУБД на удаление записи с пустым Id, которого естественно в БД нет...
По этой причине вообще отказался от использования DataTable в пользу коллекций объектов (List<Item>), но там еще больше гемороя с сортировкой и фильтрацией отображения (через BindingSource), с чем DataTable справляется на ура.
Кто-нибудь сталкивался с подобной проблемой?

PS - пытался использовать GUID для первичного ключа и сохранять его как поле TEXT, вариант очень костыльный, т.к. СУБД дополнительно еще создает столбец rowid типа INTEGER...получается хлам.
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
28.03.2015, 09:43
Ответы с готовыми решениями:

Получить первичный ключ после новой записи, как?
Как получить значение первичного ключа, сразу после новой записи в БД?

Добавление записи в базу, если в полях автоинкремент и первичный ключ
Здравствуйте! Есть 3 колонки id (первичный ключ и автоинкремент), Model, Value (автоинкремент) Создаю запрос INSERT INTO Modeli...

Замена данных в таблице по связи Первичный ключ - Вторичный ключ
Есть главная таблица и есть от нее зависимая. Требуется: чтоб в зависимую таблицу, в колонку вторичного ключа - подставились данные из...

6
 Аватар для kodv
1449 / 1121 / 347
Регистрация: 11.04.2011
Сообщений: 2,621
28.03.2015, 13:29
Castello2401, это не проблема. Это особеность. Вам нужно после выполнения INSERT'а считать вставленный id, и занести его в DataTable. По-моему, в SQLite это делается функцией last_insert_rowid. Выполнять запрос с получением результата этой функции лучше во время события SQLiteDataAdapter.RowUpdated. С телефона мне сейчас сложно подробнее объяснить. Поищите на форуме. Я точно уже несколько раз этот трюк показывал на этом форуме, только для SQL Server.
1
12 / 12 / 5
Регистрация: 06.03.2012
Сообщений: 182
28.03.2015, 14:39  [ТС]
Цитата Сообщение от kodv Посмотреть сообщение
Вам нужно после выполнения INSERT'а
На данный момент, чтобы добавить новую запись, я к DataTable добавляю DataRow и тут же выполняю метод Update у адаптера. Вы предлагаете вручную выполнять команды вставки в БД?
0
 Аватар для kodv
1449 / 1121 / 347
Регистрация: 11.04.2011
Сообщений: 2,621
28.03.2015, 15:36
Лучший ответ Сообщение было отмечено Castello2401 как решение

Решение

Castello2401, Чудес не бывает. Запись в БД можно вставить только выполнив команду INSERT. Эта команда выполняется из адаптера - этого достаточно. Вам всего лишь нужно после того, как адаптер выполнил эту команду, считать ид последней вставленной записи. После вставки/изменения/удаления каждой строки возникает событие RowUpdated, при обработке которого иожно подкорректировать обработанную строку DataTable'а.
0
12 / 12 / 5
Регистрация: 06.03.2012
Сообщений: 182
28.03.2015, 15:54  [ТС]
Вроде все понятно, код:
C#
1
2
3
4
5
void itemsTableAdapter_RowUpdated(object sender, System.Data.Common.RowUpdatedEventArgs e)
        {
            long itemId = (long)SQLiteCommand.Execute("SELECT last_insert_rowid()", SQLiteExecuteType.Scalar, connectionString);
            e.Row.SetField<long>("Id", itemId);
        }
Результат получения последнего ключа равен нулю всегда. Проверил Firefox->SQLite Manager сразу после вставки новой записи, все работает. Есть подозрения, что функция возвращает последний ключ только в текущем соединении. А так как все, что связанно с Data-Table/Row/Set это автономный уровень, то поэтому всегда нуль. Попробую открыть соединение и не закрывать его на время всей работы.
0
 Аватар для kodv
1449 / 1121 / 347
Регистрация: 11.04.2011
Сообщений: 2,621
28.03.2015, 16:03
Castello2401, Даже правила английского языка говорят, что это событие происходит после Update'а строки. Хотя может для SQLite есть своя специфика ... За компьютером окажусь, обязательно провнрю.
0
12 / 12 / 5
Регистрация: 06.03.2012
Сообщений: 182
28.03.2015, 18:07  [ТС]
Есть, заработало!
Вся проблема в соединении, функция last_insert_rowid() возвращает последний ключ ТЕКУЩЕГО соединения.
В моем случае открывалось два соединения с БД, первое открывал адаптер при обновлении:
C#
1
itemsTableAdapter = new SQLiteDataAdapter("SELECT * FROM Items", connectionString);
второе во время обновления открывал я сам:
C#
1
long itemId = (long)new SQLiteCommand("SELECT last_insert_rowid()", connectionString).ExecuteScalar();
все стало на свои места, когда я создал и открыл одно соединение, и использовал его как для адаптера, так и для своего запроса.

Добавлено через 8 минут
-----FINAL-----
Следующий код будет работать с любыми таблицами где первичный ключ называется "Id", просто вешаем на событие RowUpdated нужного адаптера.
C#
1
2
3
4
5
6
7
8
        private void SetLastInsertRowId(object sender, RowUpdatedEventArgs e)
        {
            if (e.StatementType == StatementType.Insert)
            {
                long rowId = (long)new SQLiteCommand("SELECT last_insert_rowid()", (SQLiteConnection)e.Command.Connection).ExecuteScalar();
                e.Row.SetField<long>("Id", rowId);
            }
        }
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.03.2015, 18:07
Помогаю со студенческими работами здесь

Вставка новой строки. Связь с DataTable()
Друзья, разъясните пожалуйста зачем создавать ДатаТабел? Чтобы вставить новую строчку в таблицу бд? private void OkButton_Click(object...

Первичный ключ
Всем доброго времени суток. Прошу помощи. База работы с клиентами. Случайно удалил запись (Заказчик). Все востановил (ввел все по...

Первичный ключ
Создал таблицу, которая содержит несколько колонок. Первую с названием элементов я создаю как Primary Key. При внесении данных в...

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

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru