Вернуть @@IDENTITY после INSERT для использования в качестве переменной

У меня есть функция, которую я хочу выполнить INSERT или UPDATE в зависимости от того, установлен ли ProfileID, найденный в импортированном файле .csv, на текущий идентификатор или если он новый (если он новый, то он помечен как «Новый ," "Новый1", "Новый2" и т. д. в столбце ProfileId файла).

К сожалению, во время процесса сохранения вызывается несколько функций, требующих использования файла ProfileID. Но если выполняется INSERT, то ProfileID неизвестно, когда вызываются эти функции.

Я настроил запрос INSERT для возврата ProfileID после вставки новой строки с использованием SCOPE_IDENTITY(), но я не уверен, как взять этот результат и поместить его в переменную. Есть ли способ сделать это?

Это весь код функции сохранения:

private void SaveProfile(string[] curProfile)
{  
    string profId = GetValue(curProfile, (int)ProfileColumns.ProfileId).ToLower();

    string query ="";

    using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["AbleCommerce"].ToString()))
    {
        try
        {
            if (profId.Contains("new")) 
            {
                string insertQuery = "INSERT INTO ProductProfile (Name, Description, SpeciesLink, LineDraw, LineDrawThumbnail, ProfileThumbnail, ComponentThickness, ComponentWidth, FinishedThickness, FinishedWidth, ClassificationID, StockOrCust, ComponentFactor, Visibility, Notes, OrderBy) VALUES (@Name, @Description, @SpeciesLink, @LineDraw, @LineDrawThumbnail, @ProfileThumbnail, @ComponentThickness, @ComponentWidth, @FinishedThickness, @FinishedWidth, @ClassificationID, @StockOrCust, @ComponentFactor, @Visibility, @Notes, @OrderBy) SELECT SCOPE_IDENTITY()";
                Response.Write("PERFORM INSERT<br />");
                query = insertQuery;
            }

            {
                string updateQuery = "UPDATE ProductProfile SET Name = @Name, Description = @Description, SpeciesLink = @SpeciesLink, LineDraw = @LineDraw, LineDrawThumbnail = @LineDrawThumbnail, ProfileThumbnail = @ProfileThumbnail, ComponentThickness = @ComponentThickness, ComponentWidth = @ComponentWidth, FinishedThickness = @FinishedThickness, FinishedWidth = @FinishedWidth, ClassificationID = @ClassificationID, StockOrCust = @StockOrCust, ComponentFactor = @ComponentFactor, Visibility = @Visibility, Notes = @Notes, OrderBy = @OrderBy WHERE ProfileID = @profid";
                Response.Write("PERFORM UPDATE<br />");
                query = updateQuery;
            }

            SqlCommand cmd = new SqlCommand(query, cn);
            cmd.CommandType = CommandType.Text;

            cn.Open();

            cmd.Parameters.AddWithValue("@profid", GetValue(curProfile, (int)ProfileColumns.ProfileId).Trim());
            cmd.Parameters.AddWithValue("@Name", GetValue(curProfile, (int)ProfileColumns.Name).Trim());
            cmd.Parameters.AddWithValue("@Description", GetValue(curProfile, (int)ProfileColumns.Description).Trim());
            cmd.Parameters.AddWithValue("@SpeciesLink", GetValue(curProfile, (int)ProfileColumns.SpeciesLink).Trim());
            cmd.Parameters.AddWithValue("@Linedraw", GetValue(curProfile, (int)ProfileColumns.LineDraw).Trim());
            cmd.Parameters.AddWithValue("@LineDrawThumbnail", GetValue(curProfile, (int)ProfileColumns.LineDrawThumbnail).Trim());
            cmd.Parameters.AddWithValue("@ProfileThumbnail", GetValue(curProfile, (int)ProfileColumns.ProfileThumbnail).Trim());
            cmd.Parameters.AddWithValue("@ComponentThickness", GetValue(curProfile, (int)ProfileColumns.ComponentThickness).Trim());
            cmd.Parameters.AddWithValue("@ComponentWidth", GetValue(curProfile, (int)ProfileColumns.ComponentWidth).Trim());
            cmd.Parameters.AddWithValue("@FinishedThickness", GetValue(curProfile, (int)ProfileColumns.FinishedThickness).Trim());
            cmd.Parameters.AddWithValue("@FinishedWidth", GetValue(curProfile, (int)ProfileColumns.FinishedWidth).Trim());
            cmd.Parameters.AddWithValue("@ClassificationID", GetValue(curProfile, (int)ProfileColumns.ClassificationID).Trim());

            string stockCust = GetValue(curProfile, (int)ProfileColumns.StockOrCust).ToLower();

            switch (stockCust)
            {
                case "stock":
                    stockCust = "0";
                    break;
                case "custom":
                    stockCust = "1";
                    break;
                case "discontinued":
                    stockCust = "2";
                    break;
            }

            cmd.Parameters.AddWithValue("@StockOrCust", Convert.ToInt32(stockCust));
            cmd.Parameters.AddWithValue("@ComponentFactor", GetValue(curProfile, (int)ProfileColumns.ComponentFactor).Trim());

            string Visibility = GetValue(curProfile, (int)ProfileColumns.Visibility).ToLower();

            switch (Visibility)
            {
                case "public":
                    Visibility = "0";
                    break;
                case "private":
                    Visibility = "1";
                    break;
            }

            cmd.Parameters.AddWithValue("@Visibility", Convert.ToInt32(Visibility));
            cmd.Parameters.AddWithValue("@Notes", GetValue(curProfile, (int)ProfileColumns.Notes).Trim());
            cmd.Parameters.AddWithValue("@OrderBy", GetValue(curProfile, (int)ProfileColumns.OrderBy).Trim());

            cmd.ExecuteNonQuery();

            cn.Close();

            // this is the portion of the function that makes the call to other functions to complete the save process
            int profileID = Convert.ToInt32(GetValue(curProfile, (int)ProfileColumns.ProfileId));
            SaveArtchStyle(profileID, curProfile);
            SaveAssignedItems(profileID, curProfile);
            //update dimensions
            //UpdateProductDimensions(profileID, GetValue(curProfile, (int)ProfileColumns.FinishedThickness).Trim(), GetValue(curProfile, (int)ProfileColumns.FinishedWidth).Trim());
        }
        catch (Exception ex)
        {
            ErrorLabel.Text = "There was an error with the file." + ex.ToString();
        }
    }
}

person Dejsa Cocan    schedule 13.08.2014    source источник
comment
Сара, где вы используете Param в своем cmd ..? лично я бы преобразовал весь этот sql в хранимую процедуру.   -  person MethodMan    schedule 13.08.2014
comment
Напишите хранимую процедуру с именем SaveProductProfile, которая вызывает return scope_identity() после оператора вставки. Вы можете проверить наличие существующей записи в процедуре, используя, если она существует (выберите * из ProductProfile, где Id = @Id)   -  person Jon    schedule 13.08.2014
comment
не нужно проверять, просто объявите выходную переменную, например, @KeyId int OUTPUT, затем в конце команды Insert выполните следующий SET @KeyId = SCOPE_IDENTITY() в коде C# позади убедитесь, что вы объявили выходную переменную, например, qlParameter outputParam = new SqlParameter("@KeyId", SqlDbType.Int); outputParam.Direction = ParameterDirection.Output; command.Parameters.Add(outputParam); после строки ExecuteNonQuery, которую вы хотите чтобы назначить или захватить выходную переменную из вставки, как это outputId = (int)outputParam.Value;   -  person MethodMan    schedule 13.08.2014
comment
Также обратите внимание, что ваш блок if не имеет else после него, поэтому следующий блок (update) перезаписывает вашу команду insert.   -  person D Stanley    schedule 14.08.2014


Ответы (2)


Используйте функцию ExecuteScalar(), которая возвращает идентификатор области или 0 в случае сбоя. Ознакомьтесь с документацией и примером MSDN.

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar(v=vs.110).aspx

 Int32 newProdID = 0;
 string sql =
    "INSERT INTO Production.ProductCategory (Name) VALUES (@Name); "
    + "SELECT CAST(scope_identity() AS int)";
using (SqlConnection conn = new SqlConnection(connString))
{
    SqlCommand cmd = new SqlCommand(sql, conn);
    cmd.Parameters.Add("@Name", SqlDbType.VarChar);
    cmd.Parameters["@name"].Value = newName;
    try
    {
        conn.Open();
        newProdID = (Int32)cmd.ExecuteScalar();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
person Martijn van Put    schedule 13.08.2014
comment
Хм... забыл об этом, но, похоже, это тоже может сработать. :) - person Tiny Haitian; 14.08.2014
comment
Это ответ на вопрос. Я бы использовал предложение вывода вместо scope_identity(), но технически это правильно. - person Filip De Vos; 14.08.2014
comment
Спасибо. В чем преимущество использования (по вашему мнению) предложения вывода, потому что даже когда вы используете предложение вывода, вам нужно установить @ID = scope_identity(). - person Martijn van Put; 14.08.2014
comment
Вы можете использовать insert into ProductProfile (Name) output inserted.ProductId values (@Name), он выведет новое значение идентификатора в одном операторе вместо запуска двух операторов. - person Filip De Vos; 14.08.2014
comment
Я попробовал это, и в итоге он отлично сработал для меня. Спасибо! - person Dejsa Cocan; 14.08.2014

Сара, вы должны иметь возможность добавлять и использовать что-то вроде:

cmd.Parameters.Add("@ID", SqlDbType.Int, 4).Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
//Now just read the value of: cmd.Parameters["@ID"].value

Просто убедитесь, что вы поместили параметр @ID перед командой выполнения запроса. Вы даже можете присвоить его переменной как таковой:

var insertValue = cmd.Parameters["@ID"].value

Ссылочная идея находится здесь.

ОБНОВЛЕНИЕ: я забыл добавить, что в рамках оператора вставки вам необходимо сделать следующее:

 SET @ID = SCOPE_IDENTITY();
person Tiny Haitian    schedule 13.08.2014