@@IDENTITY после того, как оператор INSERT всегда возвращает 0

Мне нужна функция, которая выполняет инструкцию INSERT в базе данных и возвращает первичный ключ Auto_Increment. У меня есть следующий код С#, но, хотя оператор INSERT работает нормально (я вижу запись в базе данных, PK генерируется правильно, а строки == 1), значение id всегда равно 0. Любые идеи о том, что может произойти не так?

    public int ExecuteInsertStatement(string statement)
    {
        InitializeAndOpenConnection();
        int id = -1;


        IDbCommand cmdInsert = connection.CreateCommand();
        cmdInsert.CommandText = statement;
        int rows = cmdInsert.ExecuteNonQuery();

        if (rows == 1)
        {
            IDbCommand cmdId = connection.CreateCommand();
            cmdId.CommandText = "SELECT @@Identity;";
            id = (int)cmdId.ExecuteScalar();
        }

        return id;
    }
    private void InitializeAndOpenConnection()
    {
        if (connection == null)
            connection = OleDbProviderFactory.Instance.CreateConnection(connectString);

        if(connection.State != ConnectionState.Open)                 
            connection.Open();
    }

В ответ на ответы я попытался:

public int ExecuteInsertStatement(string statement, string tableName)
    {
        InitializeAndOpenConnection();
        int id = -1;
        IDbCommand cmdInsert = connection.CreateCommand();
        cmdInsert.CommandText = statement + ";SELECT OID FROM " + tableName + " WHERE OID = SCOPE_IDENTITY();";
        id = (int)cmdInsert.ExecuteScalar();

        return id;
    }

но теперь я получаю сообщение об ошибке "Символы, найденные после завершения инструкции SQL"

Я использую базу данных MS Access с подключением OleDb, Provider = Microsoft.Jet.OLEDB.4.0

Ответы

Ответ 1

1) объединить инструкцию INSERT и SELECT (concatenate using ";" ) в команду 1 db

2) используйте SCOPE_IDENTITY() вместо @@IDENTITY

INSERT INTO blabla...; SELECT OID FROM table WHERE OID = SCOPE_IDENTITY()

- обновить:

как выяснилось, вопрос был связан с MS ACCESS, я нашел эту статью, которая предполагает, что просто повторное использование первой команды и установка ее CommandText - "SELECT @@IDENTITY" должно быть достаточно.

Ответ 2

Поставщик Microsoft.Jet.OLEDB.4.0 поддерживает двигатели базы данных Jet v3 и Jet v4, однако SELECT @@IDENTITY не поддерживается для Jet v3.

MSAccess 97 - это Jet v3 и не поддерживает SELECT @@IDENTITY; Он поддерживается на MSAccess 2000 и выше.

Ответ 3

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

Вы также должны всегда использовать идентификатор SCOPE_IDENTITY() not @@. Ссылка здесь

Вы должны добавить

SELECT SCOPE_IDENTITY() 

После вставки.

Ответ 4

Вы используете Jet (не SQL Server), а Jet может обрабатывать только один оператор SQL для каждой команды, поэтому вам нужно выполнить SELECT @@IDENTITY в отдельной команде, очевидно, что он использует то же соединение, что и INSERT.

Ответ 5

Я думаю, вам нужно иметь идентификатор Select @@с первой командой create - попробуйте добавить его через "; SELECT @@Identity" и .ExecuteScalar инструкцию insert

Ответ 6

Есть ли триггеры на вашей таблице, которые могут вставляться в другие таблицы? Как правило, нам не рекомендуется использовать @@Identity в пользу IDENT_CURRENT, чтобы вы могли гарантировать, что вернувшаяся идентификация предназначена для только что вставленной таблицы в.

Ответ 7

Я думаю, что идентификация @@действительна только в области действия команды - в вашем случае, когда вы выполняете "инструкцию".

Измените свой "оператор" так, чтобы сама хранимая процедура вернула значение @@IDENTITY сразу после оператора INSERT и прочитала его как код возврата выполнения хранимой процедуры.

Ответ 8

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

В SQL Server Management Studio вы можете найти это, щелкнув правой кнопкой мыши на сервере в обозревателе объектов, выберите "Свойства", а затем перейдите на страницу "Соединения". Посмотрите настройки "Параметры подключения по умолчанию"

Ответ 9

Разве большинство респондентов не забывают, что ассер не использует SQL Server?

По-видимому, MS Access 2000 и более поздние не поддерживает @@IDENTITY. Альтернативой является" Использование событие RowUpdated, вы можете определить, произошел ли INSERT, получить последнее значение @@IDENTITY и поместить его в столбец идентификатора локальной таблицы в DataSet.

И да, это для встроенного VBA в Access DB. Это все еще можно вызывать вне доступа через библиотеку объектов доступа.

Редактировать: хорошо, это поддерживается, извините за быстрый вызов раннего утра. Но остальная часть этого ответа может помочь.

Ответ 10

Если вы хотите получить значение автоматического запуска числа транзакций, которое вы вставляете, и вашей среды, следующей за 1. База данных - MsAccess. 2. Драйвер Jet4 со строкой подключения, подобной этой "Provider = Microsoft.Jet.OLEDB.4.0; Password = {0}; Источник данных = {1}; Persist Security Info = True" 3. используйте Oledb

Вы можете применить мой пример к вашему коду

OleDbConnection connection =  String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Password={0};Data Source={1};Persist Security Info=True",dbinfo.Password,dbinfo.MsAccessDBFile);
connection.Open();
OleDbTransaction transaction = null;
try{
    connection.BeginTransaction();
    String commandInsert = "INSERT INTO TB_SAMPLE ([NAME]) VALUES ('MR. DUKE')";
    OleDbCommand cmd = new OleDbCommand(commandInsert , connection, transaction);
    cmd.ExecuteNonQuery();
    String commandIndentity = "SELECT @@IDENTITY";
    cmd = new OleDbCommandcommandIndentity, connection, transaction);
    Console.WriteLine("New Running No = {0}", (int)cmd.ExecuteScalar());
    connection.Commit();
}catch(Exception ex){
    connection.Rollback();
}finally{
    connection.Close();
}   

Ответ 11

Краткий ответ:
  1. Создайте две команды, каждая из которых принимает один запрос.
  2. Первый запрос sql - это запись INSERT.
  3. Второй запрос sql: "SELECT @@Identity"; который возвращает AutoNumber.
  4. Используйте cmd.ExecuteScalar(), который возвращает первый столбец первой строки.
  5. Возвращенным результатом является значение AutoNumber, сгенерированное в текущем запросе вставки.

Ссылка на эту ссылку. Пример кода указан ниже. Обратите внимание на разницу в "SAME Connection VS NEW Connection". SAME Connection дает желаемый результат.

 class Program
{
    static string path = @"<your path>";
    static string db = @"Test.mdb";
    static void Main(string[] args)
    {
        string cs = String.Format(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}\{1}", path, db);
        // Using the same connection for the insert and the SELECT @@IDENTITY
        using (OleDbConnection con = new OleDbConnection(cs))
        {
            con.Open();
            OleDbCommand cmd = con.CreateCommand();
            for (int i = 0; i < 3; i++)
            {
                cmd.CommandText = "INSERT INTO TestTable(OurTxt) VALUES ('" + i.ToString() + "')";
                cmd.ExecuteNonQuery();

                cmd.CommandText = "SELECT @@IDENTITY";
                Console.WriteLine("AutoNumber: {0}", (int)cmd.ExecuteScalar());
            }
            con.Close();
        }
        // Using a new connection and then SELECT @@IDENTITY
        using (OleDbConnection con = new OleDbConnection(cs))
        {
            con.Open();
            OleDbCommand cmd = con.CreateCommand();
            cmd.CommandText = "SELECT @@IDENTITY";
            Console.WriteLine("\nNew connection, AutoNumber: {0}", (int)cmd.ExecuteScalar());
            con.Close();
        }
    }
}

Это должно дать отчетливый вывод:

AutoNumber: 1 <br>
AutoNumber: 2 <br>
AutoNumber: 3 <br>

New connection, AutoNumber: 0

Ответ 12

Когда вы используете Access, посмотрите эту статью из aspfaq, прокрутите вниз примерно до половины пути вниз по странице. Код в классическом ASP, но, надеюсь, принципы должны по-прежнему стоять.


Идентификатор SELECT @@Identity в конечном итоге рассматривается как отдельный сценарий выполнения, я считаю. Код, который должен работать, будет следующим:

public int ExecuteInsertStatement(string statement)
{
    InitializeAndOpenConnection();

    IDbCommand cmdInsert = connection.CreateCommand();
    cmdInsert.CommandText = statement + "; SELECT @@Identity";
    object result = cmdInsert.ExecuteScalar();

    if (object == DBNull.Value)
    {
       return -1;
    }
    else
    {
       return Convert.ToInt32(result);
    }
}

Вероятно, вам понадобится/нужно убрать конкатенацию, которая добавит 'SELECT @@Identity' в конец кода.

Ответ 13

CREATE procedure dbo.sp_whlogin
(
 @id nvarchar(20),
 @ps nvarchar(20),
 @curdate datetime,
 @expdate datetime
)

AS
BEGIN
 DECLARE @role nvarchar(20)
 DECLARE @menu varchar(255)
 DECLARE @loginid int

 SELECT     @role = RoleID
 FROM         dbo.TblUsers
 WHERE    UserID = @id AND UserPass = @ps

 if @role is not null 
 BEGIN
  INSERT INTO TblLoginLog (UserID, LoginAt, ExpireAt, IsLogin) VALUES (@id, @curdate, @expdate, 1);
  SELECT @loginid = @@IDENTITY;
  SELECT @loginid as loginid, RoleName as role, RoleMenu as menu FROM TblUserRoles WHERE RoleName = @role
 END
 else
 BEGIN
  SELECT '' as role, '' as menu
 END
END
GO