2011-09-17 37 views
0

我不得不承認,我只是打算難倒加入神祕 「+1」 我INT的....我有下面的LINQ to SQL方法 - >LINQ中生成的SQL

public static int GetLastInvoiceNumber(int empNumber) 
    { 
     using (var context = CmoDataContext.Create()) 
     { 
      context.Log = Console.Out; 

      IQueryable<tblGreenSheet> tGreenSheet = context.GetTable<tblGreenSheet>(); 
      return (tGreenSheet 
          .Where(gs => gs.InvoiceNumber.Substring(3, 4) == empNumber.ToString()) 
          .Max(gs => Convert.ToInt32(gs.InvoiceNumber.Substring(7, gs.InvoiceNumber.Length))) 
          ); 
     } 
    } 

這是從一個同事寫的SQL查詢由基於實現幾乎同樣的事情 - >

SELECT DISTINCT 
SUBSTRING([InvoiceNumber], 1, 6) AS EmpNumber, 
MAX(CAST(SUBSTRING([InvoiceNumber], 7, LEN([InvoiceNumber])) AS INT)) AS MaxInc 
FROM [CMO].[dbo].[tblGreenSheet] 
WHERE SUBSTRING([InvoiceNumber], 3, 4) = '1119' --EmployeeNumber 
GROUP BY SUBSTRING([InvoiceNumber], 1, 6) 

然而,正在生成的SQL,當我通過context.Log = Console.Out檢查是這樣的 - >

SELECT MAX([t1].[value]) AS [value] 
FROM (
    SELECT CONVERT(Int,SUBSTRING([t0].[InvoiceNumber], @p0 + 1, LEN([t0].[InvoiceNumber]))) AS [value], [t0].[InvoiceNumber] 
    FROM [dbo].[tblGreenSheet] AS [t0] 
    ) AS [t1] 
WHERE SUBSTRING([t1].[InvoiceNumber], @p1 + 1, @p2) = @p3 
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [7] 
-- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [3] 
-- @p2: Input Int (Size = 0; Prec = 0; Scale = 0) [4] 
-- @p3: Input VarChar (Size = 4; Prec = 0; Scale = 0) [1119] 

你可以看到,它實際上是相當接近與明顯的例外的一些附加+1的!

WTH?!?

我甚至證實,通過刪除生成的SQL中的+1並運行它生成與原始SQL相同的結果,它將是正確的。

那麼,我錯過了什麼或做錯了什麼?這是衆所周知的LINQ的LOL與我們這些天賦不足的程序員混在一起嗎?

回答

5

SQL Server的SUBSTRING使用基於1的索引,而string.Substring使用從零開始的索引。 + 1在基地之間映射以保留C#語義。

至於爲什麼你必須刪除+ 1才能正常工作,這對我來說是個謎。

+0

我看到...但LINQ版本根本不起作用。它嘗試返回NULL,因爲沒有任何匹配。但我知道有SQL版本的工作原理和LINQ/SQL轉儲工作沒有+ 1的 –

+0

順便說一句,謝謝你解釋它,我只是希望我知道爲什麼它不工作,然後...... –

2

@MarceloCantos答案是正確的,但這裏是解釋,爲什麼當你刪除它的工作+ 1

您已經轉換 SUBSTRING([InvoiceNumber], 3, 4)gs.InvoiceNumber.Substring(3, 4)但由於C#使用從零開始的索引,你應該實際使用gs.InvoiceNumber.Substring(2, 4)從第三個角色開始。

同樣,您應該使用gs.InvoiceNumber.Substring(6)作爲SUBSTRING([InvoiceNumber], 7, LEN([InvoiceNumber]))的替代。請注意,如果您希望所有位於索引之後的位置,則不需要在C#中指定子字符串的長度。其實gs.InvoiceNumber.Substring(7, gs.InvoiceNumber.Length)會導致ArgumentOutOfRangeException,如果你試圖單獨使用它,但現在它被轉換爲T-SQL它實際上工作。

附註SUBSTRING([InvoiceNumber], 1, 6) AS EmpNumber似乎表明它的前六個字符是EmployeeNumber,但您只查看其中的最後四個字符。可能是因爲你目前只有10000名員工,但這可能會在稍後回來。

我建議你打破上面的方法,給他們專名,以提高可讀性。例如。 getEmployeeNumber(string invoiceNumber)