Добавление данных в базу (mfc)
CDatabase base;
CString sDriver,sDsn,sSql,place;
CLoadDataFromExcel readingDriver;
sDriver = readingDriver.GetExcelDriver();
sDsn.Format("ODBC;DRIVER={%s};DSN='';DBQ=%s",sDriver,"1.mdb");
TRY
{
base.Open(NULL,false,false,sDsn);
CRecordset recset( &base );
sSql = "SELECT * FROM Данные";
recset.Open(CRecordset::forwardOnly,sSql,CRecordset::readOnly);
while( !recset.IsEOF())
recset.GetFieldValue("Type",place);
recset.MoveNext();
}
recset.Close();
base.Close();
}
CATCH(CDBException, e)
{
CDialog errorDatabase;
errorDatabase.MessageBox("Ошибка базы:"+e->m_strError,"Критическая ошибка",MB_OK|MB_ICONERROR);
}
END_CATCH;
Вот не могу понять, как, во-первых, открывать базу для изменения (имеется ввиду строка recset.Open(CRecordset::forwardOnly,sSql,CRecordset::readOnly); ) и как при добавлении данных передать эти самые данные в соответствующие поля? Ну, например:
if(recset.CanAppend())
{
recset.AddNew();
recset.Type="Имя";
recset.Update();
}
Такой вариант не проходит - компилятор ругается, что нет такого свойства - Type. Но как в таком случае поступить? В VB, насколько я помню, можно было написать: recset!Type = ... А что делать в VC++? Заранее спасибо.
1. Ctrl+W (вызов Class Wizard)
2. Страница Message Maps, кнопка Add Class(New...)
3. Выбрать базовой класс CRecordSet
...дальше думаю понятно.
И recset должен быть экз. этого класса.
Чтоб компилятор видел поле Type, нужно породить класс от CRecordSet.
1. Ctrl+W (вызов Class Wizard)
2. Страница Message Maps, кнопка Add Class(New...)
3. Выбрать базовой класс CRecordSet
...дальше думаю понятно.
И recset должен быть экз. этого класса.
Также можно через SQL, INSERT INTO и ExecuteSQL
Также можно через SQL, INSERT INTO и ExecuteSQL
согласен
2shupik
забудь про CRecordset - это всего лишь отображение записей в класс на основе твоего запроса, добовлять, удалять, обновлять только через CDatabase. например удаление:
...
CDatabase dbName;
...(OPEN DB)
CString sql("DELETE FROM name WHERE id_name=1 AND id_name=2");
dbName.ExecuteSQL(sql);
удаляем из базы данных имена с id равными 1 и 2
точно так же и обновление и добавление.
добавление
...
sql.Format("INSERT INTO name(ordername,name) VALUES (%d, '%s')", SomeI, strSomeName);
dbName.ExecuteSQL(sql);
Добавление в базу записи с именем strSomeName и с порядковым номером SomeI. САМОЕ ГЛАВНОЕ НЕ ЗАБУДЬ ПОСТАВИТЬ ОДИНАРНЫЕ КОВЫЧКИ КОГДА ДОБАВЛЯЕШЬ СТРОКУ!!!! ('%s')
согласен
2shupik
забудь про CRecordset - это всего лишь отображение записей в класс на основе твоего запроса, добовлять, удалять, обновлять только через CDatabase.
Ты не совсем прав. Если сделать класс, производный от CRecordset, то можно добавлять и модифицировать данные таблицы. CRecordset без наследования такую возможность не предоставляет
согласен
2shupik
забудь про CRecordset - это всего лишь отображение записей в класс на основе твоего запроса, добовлять, удалять, обновлять только через CDatabase. например удаление:
...
CDatabase dbName;
...(OPEN DB)
CString sql("DELETE FROM name WHERE id_name=1 AND id_name=2");
dbName.ExecuteSQL(sql);
удаляем из базы данных имена с id равными 1 и 2
точно так же и обновление и добавление.
добавление
...
sql.Format("INSERT INTO name(ordername,name) VALUES (%d, '%s')", SomeI, strSomeName);
dbName.ExecuteSQL(sql);
Добавление в базу записи с именем strSomeName и с порядковым номером SomeI. САМОЕ ГЛАВНОЕ НЕ ЗАБУДЬ ПОСТАВИТЬ ОДИНАРНЫЕ КОВЫЧКИ КОГДА ДОБАВЛЯЕШЬ СТРОКУ!!!! ('%s')
Спасибо большое, так действительно быстро и удобно. Единственное, что хотелось уточнить - а как редактировать запись таким методом ? В этом случае следует писать вот так: EDIT INTO name(...) VALUES (...) ?
Спасибо большое, так действительно быстро и удобно. Единственное, что хотелось уточнить - а как редактировать запись таким методом ? В этом случае следует писать вот так: EDIT INTO name(...) VALUES (...) ?
SET Field_Name = 'bla-bla-bla'
WHERE ID = 1;
Спасибо большое, так действительно быстро и удобно. Единственное, что хотелось уточнить - а как редактировать запись таким методом ? В этом случае следует писать вот так: EDIT INTO name(...) VALUES (...) ?
Еще одна сложность возникла - нужно удалять записи из базы не по какому-то фильтру (скажем, все записи с id таким-то), а следующим образом: есть ListCtrl, в который я загружаю все записи из базы. И теперь устанавливая курсор на определенную позицию этого списка, я хочу удалить именно эту запись. Как собственно БД сообщить, какую именно запись я намерен удалить? Ведь список может быть отсортирован в любую сторону. Нужно какое-то поле в базу завести, счетчик? И потом по этом счетчику ориентироваться? Или проще извлечь из списка текущую строку, разложить по полям и передать: DELETE FROM база WHERE поле1="значение_первого_поля" AND поле2= "значение_второго_поля"? Подскажите, пожалуйста, как бы здесь грамотно поступить.
Еще одна сложность возникла - нужно удалять записи из базы не по какому-то фильтру (скажем, все записи с id таким-то), а следующим образом: есть ListCtrl, в который я загружаю все записи из базы. И теперь устанавливая курсор на определенную позицию этого списка, я хочу удалить именно эту запись. Как собственно БД сообщить, какую именно запись я намерен удалить? Ведь список может быть отсортирован в любую сторону. Нужно какое-то поле в базу завести, счетчик? И потом по этом счетчику ориентироваться? Или проще извлечь из списка текущую строку, разложить по полям и передать: DELETE FROM база WHERE поле1="значение_первого_поля" AND поле2= "значение_второго_поля"? Подскажите, пожалуйста, как бы здесь грамотно поступить.
Проще всего каждой записи задать уникальный идентификатор, т.к. в WHERE тебе надо будет передевать значение каждого поля, потому что записи в базе могут отличаться на значение всего одного поля.
Проще всего каждой записи задать уникальный идентификатор, т.к. в WHERE тебе надо будет передевать значение каждого поля, потому что записи в базе могут отличаться на значение всего одного поля.
Получается, в моем ListCtrl всегда должен присутствовать дополнительный столбец со значениями уникального идентификатора? А скрыть его от посторонних глаз никак не удастся?
Получается, в моем ListCtrl всегда должен присутствовать дополнительный столбец со значениями уникального идентификатора? А скрыть его от посторонних глаз никак не удастся?
1) можно сделать рядом с ствоим основным списком еще один список в котором будут id элементов из основного списка. только добавлять в него элементы необходимо так же как и в основной список. потом вызываешь при инициализации диалога ф-цию GetDlgItem(IDC_LIST_ID)->ShowWindow(SW_HIDE) и список с id скрывается.
2) (как сделал я после многих лет мучения с первым вариантом) пишешь производный класс от CListBox, разрисовываешь как тебе нравится потом делаешь дополнительное поле скажем типа int для каждого айтема и хранишь в этом поле любую информацию в том числе и id элементов таблици.
1) можно сделать рядом с ствоим основным списком еще один список в котором будут id элементов из основного списка. только добавлять в него элементы необходимо так же как и в основной список. потом вызываешь при инициализации диалога ф-цию GetDlgItem(IDC_LIST_ID)->ShowWindow(SW_HIDE) и список с id скрывается.
2) (как сделал я после многих лет мучения с первым вариантом) пишешь производный класс от CListBox, разрисовываешь как тебе нравится потом делаешь дополнительное поле скажем типа int для каждого айтема и хранишь в этом поле любую информацию в том числе и id элементов таблици.
У себя я просто сделал одно поле нулевой ширины и заносил туда ID строки. Еще запретил изменять его ширину. Для пользователя оно не видно и никак не обрабатывается
У себя я просто сделал одно поле нулевой ширины и заносил туда ID строки. Еще запретил изменять его ширину. Для пользователя оно не видно и никак не обрабатывается
Спасибо - идея отличная. Только вот у меня не ListBox и не пойму, как в ListCtrl вытянуть номер выделенной строки. В ListBox я делал примерно так:
CListBox m_InputList;
CString st;
int ab=m_InputList.GetCurSel();
m_InputList.GetText(ab,st);
А с ListCtrl такой фокус не проходит. Какой из его методов делает нечто похожее?
Спасибо - идея отличная. Только вот у меня не ListBox и не пойму, как в ListCtrl вытянуть номер выделенной строки. В ListBox я делал примерно так:
CListBox m_InputList;
CString st;
int ab=m_InputList.GetCurSel();
m_InputList.GetText(ab,st);
А с ListCtrl такой фокус не проходит. Какой из его методов делает нечто похожее?
Вот так например:
{
POSITION p = m_listKlient.GetFirstSelectedItemPosition();
//CListCtrl m_listKlient;
int nSelected = m_listKlient.GetNextSelectedItem(p);
CString str;
str.Format(_T("%s"), m_listKlient.GetItemText(nSelected, 7));
//7- номер столбца в котором ты хранишь ID строки
m_klientId = atol(str);
// long m_klientId; Теперь эта переменная сожержит ID
}
У себя я просто сделал одно поле нулевой ширины и заносил туда ID строки. Еще запретил изменять его ширину. Для пользователя оно не видно и никак не обрабатывается
ну это понятно, а если у тебя CListBox а не СListCtrl?
ну это понятно, а если у тебя CListBox а не СListCtrl?
С каждым элементом CListBox/CListCtrl может быть связано DWORD значение.
GetItemData/SetItemData.
Обычно для сохранения ID записей используют эту возможность.
Для сохранения указателей есть еще GetItemDataPtr/SetItemDataPtr.
С каждым элементом CListBox/CListCtrl может быть связано DWORD значение.
GetItemData/SetItemData.
Обычно для сохранения ID записей используют эту возможность.
Для сохранения указателей есть еще GetItemDataPtr/SetItemDataPtr.
ликбез одним словом.