Для многих это уже наверное избитая тема, а я с этим столкнулся впервые.
Есть таблица ключевое поле в которой счетчик, мне нужно получить значение счетчика для только что добавленной записи в таблицу.
Таблица у меня в Access-е, не использовал SQL потому что в нем нет необходимости уж слишком он громоздкий для моей задачки, а через dbf не умею
Я попробовал как советует Сеппа в "Microsoft ADO.NET" через событие Row.Updated, но "SELECT @@IDENTITY" выдает 0
ниже отрывок моего кода добавления записи в таблицу с попыткой извлечь значение счетчика:
public partial class Form1 : Form
{
string strConString = Procedures.strConectionString;
OleDbConnection odbConString1 = null;
OleDbCommand cmdGetIdentity = null;
OleDbDataAdapter ClientName_DA;
public Form1()
{
InitializeComponent();
odbConString1 = new OleDbConnection(strConString);
cmdGetIdentity = new OleDbCommand("SELECT @@IDENTITY", odbConString1);
}
void FillDB(string strName, string strAdress)
{
string strSQL = "SELECT ID, Cl_Name FROM ClientName";
ClientName_DA = new OleDbDataAdapter(strSQL, odbConString1);
ClientName_DA.RowUpdated += new OleDbRowUpdatedEventHandler(HandleRowUpdated);
DataSet DS = new DataSet();
ClientName_DA.Fill(DS, "ClientName");
DataTable DT = DS.Tables["ClientName"];
DT.PrimaryKey = new DataColumn[] { DT.Columns[0] };
DT.Columns[0].AutoIncrement = true;
DT.Columns[0].AutoIncrementSeed = -1;
DT.Columns[0].AutoIncrementStep = -1;
DataRow row =DT.NewRow();
row[1] = strName;
DT.Rows.Add(row);
if (AcceptClientNameTableChangings(DT.Select("", "", DataViewRowState.Added)))
Procedures.MessageWindow("Succsefully Added", 2, 1);
}
private void HandleRowUpdated(object sender, OleDbRowUpdatedEventArgs e)
{
if ((e.Status == UpdateStatus.Continue) && (e.StatementType == StatementType.Insert))
{
int index=(int)cmdGetIdentity.ExecuteScalar();
e.Row["ID"] = index;
MessageBox.Show("New index is "+index);
e.Row.AcceptChanges();
}
}
OleDbCommand InsertIntoClientNameTable()
{
string strSQL = "INSERT INTO ClientName (Cl_Name) VALUES (?)";
OleDbConnection odbConString1 = new OleDbConnection(strConString);
OleDbCommand cmd = new OleDbCommand(strSQL, odbConString1);
OleDbParameterCollection pc = cmd.Parameters;
pc.Add("@Cl_Name", OleDbType.VarChar, 0, "Cl_Name");
return cmd;
}
public bool AcceptClientNameTableChangings(DataRow[] dRows)
{
try
{
// если убрать принудительное открытие, то на запрос "SELECT @@IDENTITY" прога вылетает с ошибкой,
// "подключение не открыто"
odbConString1.Open();
ClientName_DA.InsertCommand = InsertIntoClientNameTable();
ClientName_DA.UpdateCommand = UpdateClientNameTable();
ClientName_DA.DeleteCommand = DeleteFromClientNameTable();
ClientName_DA.Update(dRows);
odbConString1.Close();
return true;
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Ошибка!", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
private void obAdd_Click(object sender, EventArgs e)
{
FillDB(otbName.Text, "");
}
}
Если в открытой базе с помощью Access'а у тебя при добавлении строк у тебя инкрементится счетчик и сам добавляется, то
Смотри комментарий в тексте...
M>
M>public partial class Form1 : Form
M> {
M> string strConString = Procedures.strConectionString;
M> OleDbConnection odbConString1 = null;
M> OleDbCommand cmdGetIdentity = null;
M> OleDbDataAdapter ClientName_DA;
M> public Form1()
M> {
M> InitializeComponent();
//вот здесь, скорее всего надо использовать RecordSet,
//потому как COmmand не возвращает результатов - он возвращает количество реально
//обратотанных записей (или что-то в этом духе).
//т.е. вместо
M> odbConString1 = new OleDbConnection(strConString);
M> cmdGetIdentity = new OleDbCommand("SELECT @@IDENTITY", odbConString1);
//нужно написать(за синтаксис не ручаюсь -JScript, как правильно посмотришь в MSDN):
odbConString1 = new OleDbConnection(strConString);
rsGetIdentity = new OleDbRecordset("SELECT @@IDENTITY", odbConString1);
if (!rsGetIdentity.BOF && rsGetIdentity.EOF)
{
int Identity = rsGetIdentity.Fields(0).Value;
}
M> }
M> void FillDB(string strName, string strAdress)
M> {
M> }
M> private void HandleRowUpdated(object sender, OleDbRowUpdatedEventArgs e)
M> {
M> }
M> OleDbCommand InsertIntoClientNameTable()
M> {
M> }
M> public bool AcceptClientNameTableChangings(DataRow[] dRows)
M> {
M> try
M> {
M> }
M> private void obAdd_Click(object sender, EventArgs e)
M> {
M> }
M> }
M>
M>ЗЫЖ: не судите строго Я только учусь
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Проблема с получением счетчика в Access-e
От:
Аноним
Дата:
20.02.07 04:57
Оценка:
Здравствуйте, tyger, Вы писали:
T>Здравствуйте, Mondorro, Вы писали:
T>Если в открытой базе с помощью Access'а у тебя при добавлении строк у тебя инкрементится счетчик и сам добавляется, то T>Смотри комментарий в тексте...
Да в Access-е счетчик инкрементируется, но свои значения я туда не вписываю.
M>> public Form1()
M>> {
M>> InitializeComponent();
T>//вот здесь, скорее всего надо использовать RecordSet,
T>//потому как COmmand не возвращает результатов - он возвращает количество реально
T>//обратотанных записей (или что-то в этом духе).
T>//т.е. вместо
M>> odbConString1 = new OleDbConnection(strConString);
M>> cmdGetIdentity = new OleDbCommand("SELECT @@IDENTITY", odbConString1);
T>//нужно написать(за синтаксис не ручаюсь -JScript, как правильно посмотришь в MSDN):
T> odbConString1 = new OleDbConnection(strConString);
T> rsGetIdentity = new OleDbRecordset("SELECT @@IDENTITY", odbConString1);
Но в C# нету OleDbRecordset...
И замену ему я не нашел или плохо искал
RecordSet это же вроде VB? Но в VB.Net такой функции тоже вроде как нет...
Куда копать? MSDN на этот счет вроде отмалчивается...
T> if (!rsGetIdentity.BOF && rsGetIdentity.EOF)
T> {
T> int Identity = rsGetIdentity.Fields(0).Value;
T> }
M>> }
Здравствуйте, tyger, Вы писали:
T>Здравствуйте, Mondorro, Вы писали:
T>Если в открытой базе с помощью Access'а у тебя при добавлении строк у тебя инкрементится счетчик и сам добавляется, то T>Смотри комментарий в тексте...
Access у меня закрыт, и предполагается что юзер в дальнейшем не будет туда лазить для правки.
M>> public Form1()
M>> {
M>> InitializeComponent();
T>//вот здесь, скорее всего надо использовать RecordSet,
T>//потому как COmmand не возвращает результатов - он возвращает количество реально
T>//обратотанных записей (или что-то в этом духе).
T>//т.е. вместо
M>> odbConString1 = new OleDbConnection(strConString);
M>> cmdGetIdentity = new OleDbCommand("SELECT @@IDENTITY", odbConString1);
T>//нужно написать(за синтаксис не ручаюсь -JScript, как правильно посмотришь в MSDN):
T> odbConString1 = new OleDbConnection(strConString);
T> rsGetIdentity = new OleDbRecordset("SELECT @@IDENTITY", odbConString1);
Но в C# нету OleDbRecordset...
И замену ему я не нашел или плохо искал
RecordSet это же вроде VB? Но в VB.Net такой функции тоже вроде как нет...
Куда копать? MSDN на этот счет вроде отмалчивается...
T>if (!rsGetIdentity.BOF && rsGetIdentity.EOF)
T> {
T> int Identity = rsGetIdentity.Fields(0).Value;
T> }
M>> }
Здравствуйте, Mondorro, Вы писали:
T>>Если в открытой базе с помощью Access'а у тебя при добавлении строк у тебя инкрементится счетчик и сам добавляется, то T>>Смотри комментарий в тексте... M>Access у меня закрыт, и предполагается что юзер в дальнейшем не будет туда лазить для правки.
Я это говорил к тому, чтобы ты проверил, что в самой базе у тебя все правильно сделано — правильный тип у столбца выставлен.
Ясно, глянул я в MSDN...
Правильный вариант должен выглядеть так: M>
M>>> public Form1()
M>>> {
M>>> InitializeComponent();
using (OleDbConnection connection = new OleDbConnection(strConString))
{
OleDbCommand command = new OleDbCommand("SELECT @@IDENTITY", connection);
connection.Open();
OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
int Identity = reader[0];
}
reader.Close();
}
M>>> }
M>
Здравствуйте, tyger, Вы писали:
T>Ясно, глянул я в MSDN... T>Правильный вариант должен выглядеть так:
Где ты это нашел? У меня вроде установлена MSDN, но я в ней видно искать совсем не умею...
public Form1()
{
InitializeComponent();
using (OleDbConnection connection = new OleDbConnection(strConString))
{
..............[пофиксино]...................
}
}
Кстати если я в таком ввиде впишу в конструктор класса, то Identity сразу при загрузке 0 выдаст, так как добавления не было.
Запихал немного измененную конструкцию в RowUpdated все равно ноль.
ИМХО ExecuteReader и ExecuteScalar, особо не отличаются в плане возвращения данных. Грубо говоря Scalar одно значение вовзращает Reader-несколько.
ЗЫЖ Скажи где ты это в MSDN нарыл попробую сам поискать...
Здравствуйте, Mondorro, Вы писали:
M>Кстати если я в таком ввиде впишу в конструктор класса, то Identity сразу при загрузке 0 выдаст, так как добавления не было. M>Запихал немного измененную конструкцию в RowUpdated все равно ноль. M>ИМХО ExecuteReader и ExecuteScalar, особо не отличаются в плане возвращения данных. Грубо говоря Scalar одно значение вовзращает Reader-несколько.
Строка подключения у тебя правильная, разве что для острастки можешь добавить логин пароль....
Ниже кусок моего кода правда на JScript (ASP), но через ADO, т.е. суть использования должна быть тебе в принципе ясна...
Я думаю, что возврат @@IDENTITY — это работа JET-драйвера, и от языка или среды исполнения зависеть не должен...
Может ты коннекты закрываешь и открываешь каждый раз? Тогда @@IDENTITY потеряется...
if ( nn_client_id == 0)
{
var cmdApp = Server.CreateObject("ADODB.Command");
cmdApp.ActiveConnection = tp_conn;
cmdApp.CommandText = "INSERT INTO clients (short_company_name,address,phone,phone1,info) "+
"VALUES ('"+sn_sh_company_name+"','"+sn_address+"','"+sn_phone+"','"+sn_phone1+"','"+sn_info+"');";
cmdApp.Execute;
cmdApp = null;
var rsApp = Server.CreateObject("ADODB.Recordset");
rsApp.Open("SELECT @@IDENTITY", tp_conn);
if (!rsApp.BOF && !rsApp.EOF)
{
nn_client_id = Number(rsApp.Fields(0).Value);
Response.Write ("<br/>Addeid client with code = "+nn_client_id+"<br/>");
}
if (rsApp.State == adStateOpen)
rsApp.Close;
rsApp = null;
}//if (isNaN(nn_client_id ...
Передрал все один в один из MSDN-а и заработала СЦУКА!
Спасибо за советы. Сам бы дольше наверное докапывался до истины...
Сейчас буду разбираться где у меня косяк. Где-то теряется соединение как ты и сказал, Обновление проходит успешно, но вот индекс не получаю.
Судя по всему создаю много ненужных подключений.
Главное, что MSDN-овское работает, значит не пропаду.
Здравствуйте, Mondorro, Вы писали:
M>Здравствуйте, tyger, Вы писали:
M>Передрал все один в один из MSDN-а и заработала СЦУКА!
M>Спасибо за советы. Сам бы дольше наверное докапывался до истины... M>Сейчас буду разбираться где у меня косяк. Где-то теряется соединение как ты и сказал, Обновление проходит успешно, но вот индекс не получаю. M>Судя по всему создаю много ненужных подключений. M>Главное, что MSDN-овское работает, значит не пропаду.
И у себя разобрался!
Все было как всегда просто. всего одну строчку закоментил и работает