LINQ 增添神秘感“1”到生成的 SQL 中我的 int
我不得不承认,我只是计划被难住了......我有下面的 LINQ to 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)
然而,当我通过 context.Log = Console.Out
检查时,正在生成的 SQL 是这样的 -->
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]
您可以看到,除了GLARING添加了一些+1
之外,它实际上相当接近!
WTH?!?
我什至通过删除生成的 SQL 中的 +1
并运行它来验证它是否正确,生成与原始 SQL 相同的结果。
那么,我错过了什么或做错了什么?这是众所周知的 LINQ 的做法吗?LOL 是为了对付我们这些才华横溢的程序员吗?
I have to admit, I am just plan stumped....I have the below LINQ to SQL Method -->
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)))
);
}
}
This was made based from a SQL query written by a co-worker to achieve nearly the same thing -->
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)
However, the SQL that is being generated, when I check through context.Log = Console.Out
is this-->
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]
You can see that it is actually fairly close with the GLARING exception of some added +1
's!!!
WTH?!?
I even verified that it WOULD be correct by removing the +1
's in the generated SQL and running it with it generating the same results as the original SQL.
So, what am I missing or doing wrong? Is this a well know LOL of LINQ's to screw with us less talented programmers?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
SQL Server 的 SUBSTRING 使用从 1 开始的索引,而
string.Substring
使用从 0 开始的索引。+ 1
在基数之间进行映射以保留 C# 语义。至于为什么必须删除
+ 1
才能使其正常工作,这对我来说是个谜。SQL Server's SUBSTRING uses 1-based indexing, whereas
string.Substring
uses zero-based indexing. The+ 1
maps between the bases to preserve the C# semantics.As to why you had to remove the
+ 1
to make it work correctly, that's a mystery to me.@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(stringinvoiceNumber)
等。@MarceloCantos answer is correct, but here is the explanation as to why it works when you remove the
+ 1
:You have converted
SUBSTRING([InvoiceNumber], 3, 4)
togs.InvoiceNumber.Substring(3, 4)
but since C# uses zero-based index you should actually usegs.InvoiceNumber.Substring(2, 4)
to start at the third character.Similarly you should use
gs.InvoiceNumber.Substring(6)
as the substitution forSUBSTRING([InvoiceNumber], 7, LEN([InvoiceNumber]))
. Note that there is no need to specify the length of the substring in C# if you want all that is after the index. Actuallygs.InvoiceNumber.Substring(7, gs.InvoiceNumber.Length)
would cause anArgumentOutOfRangeException
if you tried to use it separately, but now that it is translated to T-SQL it actually works.On a side note
SUBSTRING([InvoiceNumber], 1, 6) AS EmpNumber
seems to indicate that it the first six characters are theEmployeeNumber
but you are only looking at the last four of them. Presumably because you only have < 10000 Employees at the moment, but this might come back to bite you later.I would suggest you break out the methods above and give them proper names, to enhance readability. E.g.
getEmployeeNumber(string invoiceNumber)
, etc.