簡體   English   中英

如何在單個事務中執行多個原始SQL命令?

[英]How to execute multiple raw SQL commands in a single transaction?

我需要使用.net core應用將幾個值插入幾個表中。

第一個表 [AI_Table]包含鍵, 第二個表[AI_TableLanguage]包含多種語言的名稱。 [AI_Table]具有IDENTITY主鍵,因此DB會生成它。 我需要從[AI_Table]獲取該密鑰並將其插入[AI_TableLanguage]。

首先,我不確定獲取最大密鑰是正確的方法,其次,如果兩個或更多用戶同時訪問該表怎么辦? 它會陷入僵局,還是什么? 所以我的問題是,或者不是,這個http post操作結果如何充當一個事務,所以沒有人可以中斷這些插入?

大概的概念:

  • 插入[AI_Table](DB生成PK)。
  • 獲取該PK並將其插入[AI_TableLanguage] 3次。

我閱讀了其他一些得到解答的問題,還閱讀了Microsoft文檔。 我找不到使用RAW SQL的任何答案。 另外,我找不到整個IActionResult是否充當單個事務。

[HttpPost, ActionName("Create")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(IzvorDropDown IzvorDropDown, InstitucijaDropDown InstitucijaDropDown, UpitTabeleCreate UpitTabeleCreate)
{
    //insert
    await context.Database.ExecuteSqlCommandAsync($"INSERT INTO AI_Table (IAICode, VOD, VDO, user_insert, user_update, date_insert, date_update) VALUES ({IzvorDropDown.IAIcode},{UpitTabeleCreate.VOD},{UpitTabeleCreate.VDO},{TrenutniKorisnik},{TrenutniKorisnik},{TrenutnoVreme},{TrenutnoVreme})");            

    //get max key
    var item = await context.NextIAITableCodeGenerator.FromSql($"SELECT ISNULL(MAX(IAITableCode), 0) AS NextIAIcode FROM AI_Table").ToListAsync();
    int IAITableCode = item[0].NextIAIcode;     

    //insert continue
    await context.Database.ExecuteSqlCommandAsync($"INSERT INTO AI_TableLanguage (IAITableCode, LanguageID, TableName) VALUES ({IAITableCode},1,{UpitTabeleCreate.TableNameCyr})");  //cirilica - radi
    await context.Database.ExecuteSqlCommandAsync($"INSERT INTO AI_TableLanguage (IAITableCode, LanguageID, TableName) VALUES ({IAITableCode},2,{UpitTabeleCreate.TableNameLat})"); //latinica
    await context.Database.ExecuteSqlCommandAsync($"INSERT INTO AI_TableLanguage (IAITableCode, LanguageID, TableName) VALUES ({IAITableCode},3,{UpitTabeleCreate.TableNameEng})"); //engleski

    return RedirectToAction(nameof(Index));
}

代碼本身有效。 它可以正確地插入數據庫,但是當有許多用戶試圖同時訪問這些表時,我不知道它是否會繼續這樣做。

您認為這將導致並發問題是正確的。

使用存儲過程並搜索如何使用SCOPE_IDENTITY

數據庫在提交日志上工作。 並且在每次提交中,數據庫都會檢查記錄(或序列)的最終版本(狀態)以及提交日志本身提供的版本號,如果這些信息之間存在不一致之處,則可能會出現類似“此記錄已被自您啟動以來被其他用戶更改” 因此,它與一個單一的承諾 ,使這些(互相在一個事務相關的)插入/更新/刪除操作是很重要的。 這樣您就可以使用數據庫的一致性機制,並可以確定在任何負載情況下代碼的行為。

一種確保100%獲得正確身份的方法是使用OUTPUT子句文檔

在此示例中, FieldID是表TableXYZ的IDENTITY KEY

存儲過程示例:

USE [DataBaseX]
GO
IF OBJECT_ID('spTableXYZAdd') IS NOT NULL
    DROP PROC spTableXYZAdd
GO

CREATE PROCEDURE dbo.spTableXYZAdd
                @FieldOne int,
                @FieldTwo int,
                @FieldThree DateTime,
                @ReturnIdentityValue int OUTPUT

AS
BEGIN

        DECLARE @TempTableXYZ table ( TempID int )

        INSERT INTO TableXYZ (FieldOne,FieldTwo,FieldThree) 
        OUTPUT INSERTED.FieldID into @TempTableXYZ
        VALUES (@FieldOne,@FieldTwo,@FieldThree)

        SELECT @ReturnIdentityValue = (SELECT TempID FROM @TempTableXYZ)
END
GO

您的代碼將如下所示:

public static int AddSomeRecord(RecordClass oRecordObj)
{
    int iRetVal = 0;
    using (SqlConnection conn = Connection.GetConnection())
    {
        using (SqlCommand cmd = new SqlCommand("spTableXYZAdd", conn))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("@FieldOne", oRecordObj.FieldOne);
            cmd.Parameters.AddWithValue("@FieldTwo", oRecordObj.FieldTwo);
            cmd.Parameters.AddWithValue("@FieldThree", oRecordObj.FieldThree);
            cmd.Parameters.Add("@ReturnIdentityValue", SqlDbType.Int).Direction = ParameterDirection.Output;
            conn.Open();
            cmd.ExecuteNonQuery();
            iRetVal = Convert.ToInt32(cmd.Parameters["@ReturnIdentityValue"].Value);
        }
    }
    return iRetVal;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM