2

我認爲在很多情況下這是一個普遍的問題,但我還沒有在網上找到正確的答案。在我的MVC應用程序,我有以下表格:如何在創建新記錄之前獲取最大ID值?

問題表:

--------------------------------------------- 
IssueID (pk) | CategoryID (fk) | IssueNumber 
--------------------------------------------- 
    1   |  1   |  1 
    2   |  1   |  2 
    3   |  2   |  1 
    4   |  1   |  3 


分類表:

----------------------------------- 
CategoryID (pk) | Prefix | Name 
----------------------------------- 
    1   | COM | Computer 
    2   | GEN | General 


在這裏我用IssueID(主鍵)兩個類別(COM和GEN)的字段。另一方面,我想依次生成IssueNumber(1,2,3 ...),而沒有任何CategoryID的間隙。另一方面,我也想從上面創建的另一個類別創建IssueNumber。所以問題是:

1)有沒有關於上述方法的問題?如果是這樣,你對此有什麼建議?

2)在創建記錄之前,我應該如何獲取IssueNumber的最大值?我想在SaveChanges()方法(我使用實體框架)上做到這一點。由於我不會將IssueNumber字段設置爲PK,因此我無法使MsSQL Server自動遞增此列值。

任何幫助,將不勝感激。提前致謝。


更新:

這是通過使用lambda解決方案:

public int SaveIssue(Issue issue) 
{ 
    int max = context.Issues.Where(m => m.CategoryID == issue.CategoryID).Max(m => m.IssueNumber); 
    issue.IssueNum = max + 1; 

    context.Issues.Add(issue); 
    context.SaveChanges(); 
    return issue.IssueNum ; 
} 
+0

但我沒有將IssueNumber字段設置爲PK,我想爲類別創建最大值+1。所以,在創建一個新的ID之前應該記住CategoryID字段。你能解釋如何做到這一點? –

+1

@DavidW問題不在於如何自動生成密鑰,而是詢問如何自動生成'IssueNumber',它遵循'RowNumber()over(由CategoryID分區,按IssueID排序)'模式。 –

+0

@ScottChamberlain絕對正確,斯科特。我誤解了這個問題。謝謝。 –

回答

5

我不知道如何在EF做到這一點,但通過SQL可以做到這一點通過以下(我假設IssueID是一個標識列)

CREATE PROCEDURE usp_CreateNewIssue 
    @catagoryId int, 
    @issueId int OUTPUT, 
    @issueNumber int OUTPUT 
AS 
BEGIN 
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 
    BEGIN TRANSACTION 
     declare @maxId int   
     declare @newRow table (IssueID int NOT NULL, IssueNumber int NOT NULL) 

     select @maxId = MAX(IssueNumber) from Issue where CategoryID = @catagoryId 

     Insert Into Issue (CategoryID, IssueNumber) values (@catagoryId, @maxId + 1) 
      OUTPUT INSERTED.IssueID, INSERTED.IssueNumber 
      INTO @newRow 

     select @issueId = IssueID, @issueNumber = IssueNumber from @newRow 
    COMMIT TRANSACTION 
END 

(代碼寫在瀏覽器和未經測試的語法錯誤)

使用SET TRANSACTION ISOLATION LEVEL SERIALIZABLE確保您閱讀MAX(IssueNumber)後無其他查詢可以修改結果,直到您提交事務之後。

注意:要獲得良好性能,請確保CategoryID已在Issue上編入索引,以便SQL引擎可以對其執行Key-Range lock而不是表鎖。

+0

我認爲FluentAPI可能允許一種機制通過MapToStoredProcedures聲明關閉DBModelBuilder對象,這可以通過OnModelCreating事件的重寫來訪問此類過程... –

+0

@Scott Chamberlain:非常感謝您的回覆。爲了簡化,我使用lambda表達式解決了問題,如更新後的代碼所示。投票+ –