12 / 12 / 5
Регистрация: 06.03.2012
Сообщений: 182
SQLite

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

28.03.2015, 09:43. Показов 4493. Ответов 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
Ответ Создать тему
Опции темы

Новые блоги и статьи
Валидация и контроль данных табличной части документа перед записью
Maks 22.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в КА2. Задача: контроль и валидация данных табличной части документа перед записью с учетом регламента компании. . .
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: разработка отчёта по затраченным материалам за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В. . .
Отчёт о спецтехнике находящейся в ремонте
Maks 20.04.2026
Отчёт из решения ниже размещен в конфигурации КА2. Задача: отобразить спецтехнику, которая на данный момент находится в ремонте. Есть нетиповой документ "Заявка на ремонт спецтехники" который. . .
Памятка для бота и "визитка" для читателей "Semantic Universe Layer (Слой семантической вселенной)"
Hrethgir 19.04.2026
Сгенерировано для краткого описания по случаю сборки и компиляции скелета серверного приложения. И пусть после этого скажут, что статьи сгенерированные AI - туфта и не интересно. И это не реклама -. . .
Запрет удаления строк ТЧ документа при определённом условии
Maks 19.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "Аккумуляторы", разработанного в конфигурации КА2. У данного документа есть ТЧ, в которой в зависимости от прав доступа. . .
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут Суть: - Группа наркоманов из 10 человек. - Только один инфицирован ВИЧ. - Колются одной иглой. - Колются раз в день. - Колются последовательно через. . .
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru